Skip to content

bgriffen/PythonGUITemplate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Python GUI Template

A batteries-included starting point for scientific desktop GUIs in Python, built on Traits, TraitsUI, Matplotlib and Mayavi.

CI Python License: MIT Code style: ruff

Clone it, run it, then replace the example panels with your own. You get a resizable two-pane window with an embedded Matplotlib canvas (including the standard navigation toolbar), an optional Mayavi 3D scene, and tabbed control panels wired to the display — all of which usually take a frustrating afternoon to assemble from scratch.

Features

  • Embedded Matplotlib canvas with the full navigation toolbar, in a resizable split pane.
  • Runs under Qt or wx. The Matplotlib editor picks the right canvas for whichever ETS toolkit is active, so you are not locked into wxPython.
  • Optional 3D. Mayavi powers a 3D scene tab when installed; when it is not, the tab degrades to an install hint and everything else keeps working.
  • Live-updating controls. Marker colour, style and size apply to the current plot immediately; panel controls redraw as you drag them.
  • Two worked example panels covering the editors you will actually reach for — ranges, enums, booleans, buttons, directory and file pickers, enabled_when, read-only readouts and CSV export.
  • Tested and linted, with a headless pytest suite and CI.

Requirements

  • Python 3.9 or newer
  • One GUI toolkit: Qt (recommended) or wx
  • TraitsUI 7.2+ — older versions render black backgrounds and other oddities

Installation

git clone https://github.com/bgriffen/PythonGUITemplate.git
cd PythonGUITemplate
python -m venv .venv && source .venv/bin/activate

Then install with the toolkit you want. Pick one:

pip install -e '.[qt]'    # Qt via PySide6 - recommended, installs cleanly everywhere
pip install -e '.[wx]'    # wxPython - the original backend

Qt is the easier of the two to install; wxPython frequently needs to build from source on Linux. If you install both, set ETS_TOOLKIT=qt (or wx) to say which one wins.

Optional: the 3D scene

pip install -e '.[qt,3d]'

This pulls in Mayavi and VTK — a large download and the most fragile part of the stack. It is entirely optional: without it the app runs normally and the Mayavi tab shows installation instructions instead.

Running

python main.py

or, equivalently:

python -m pyguitemplate
pyguitemplate              # console script, after installing

On macOS with the wx backend you may need pythonw main.py instead, so the process is treated as a proper windowed application. This is not necessary under Qt.

Project layout

pyguitemplate/
├── app.py               # ApplicationMain: the window, the split layout, shared plot state
├── mpl_editor.py        # Toolkit-agnostic TraitsUI editor embedding a Matplotlib figure
├── scene.py             # Mayavi 3D tab, with a fallback when Mayavi is missing
├── colors.py            # ColorTrait -> Matplotlib colour conversion
└── panels/
    ├── first_panel.py   # Example: a tour of the common Traits editors
    └── second_panel.py  # Example: a small signal generator with CSV export
tests/                   # Headless pytest suite
main.py                  # Launcher

Adding your own panel

Panels are plain HasTraits classes. They receive the ApplicationMain instance so they can drive the shared display, and they declare a View that lays out their controls.

# pyguitemplate/panels/my_panel.py
import numpy as np
from traits.api import Any, Button, HasTraits, Range
from traitsui.api import Item, View


class MyPanel(HasTraits):
    main = Any()

    exponent = Range(1.0, 4.0, 2.0)
    plotbutton = Button("Plot")

    view = View(
        Item("exponent", label="Exponent"),
        Item("plotbutton", show_label=False),
    )

    def replot(self):
        x = np.linspace(0.0, 5.0, 200)
        self.main.plot(x, x**self.exponent)

    # Traits calls this automatically whenever `exponent` changes.
    def _exponent_changed(self):
        self.replot()

    def _plotbutton_fired(self):
        self.replot()

    def __init__(self, main, **kwargs):
        super().__init__(**kwargs)
        self.main = main

Then register it in app.py — add an Instance trait, a _my_panel_default factory, and an Item in right_panel:

my_panel = Instance(MyPanel)

def _my_panel_default(self):
    return MyPanel(self)

right_panel = Tabbed(
    ...,
    Item("my_panel", style="custom", label="My Tab", show_label=False),
)

Two conventions worth following:

  • Plot through main.plot(x, y) rather than touching the figure yourself. It records the line it draws, which is what lets the marker controls restyle it afterwards.
  • Run colours through to_mpl_color() if you read a ColorTrait. TraitsUI stores a toolkit-native QColor/wx.Colour, and Matplotlib rejects both.

Testing

pip install -e '.[qt,dev]'
pytest

The suite never opens a window — it builds the trait objects and inspects the Matplotlib figure directly — so it runs headless. On a machine with no display, set QT_QPA_PLATFORM=offscreen.

ruff check .          # lint
ruff format .         # format

Troubleshooting

Symptom Cause and fix
ImportError naming a toolkit on startup No GUI toolkit installed. pip install -e '.[qt]'.
Black backgrounds, misdrawn widgets TraitsUI older than 7.2. Upgrade it.
Mayavi tab shows an install hint Expected without Mayavi. pip install -e '.[qt,3d]' to enable it.
Wrong toolkit picked when both installed Set ETS_TOOLKIT=qt or ETS_TOOLKIT=wx.
Window does not focus on macOS (wx) Launch with pythonw main.py, or use the Qt backend.
qt.qpa.plugin errors on a headless Linux box Set QT_QPA_PLATFORM=offscreen.

Further reading

License

MIT — see LICENSE.

About

A batteries-included starting point for scientific desktop GUIs in Python, built on Traits, TraitsUI, Matplotlib and Mayavi.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages