Pyzed vs Dear PyGui
Dear PyGui wraps Dear ImGui, the immediate-mode toolkit used for debug tools in game engines. It is GPU-drawn and very fast, and it shines for real-time plots, node editors and internal tools. Its look is the ImGui “tool” look, and it redraws continuously, which suits a dashboard that changes every frame more than a form that changes when you click.
In short
Section titled “In short”| Pyzed | Dear PyGui | |
|---|---|---|
| Model | State + view() (Elm architecture) |
Items created once with tags, changed with set_value / configure_item |
| Redraws | When something changes | Every frame, by default |
| Look | Modern ready-made components, themes, dark mode | ImGui tool style, configurable with themes |
| Text | Full shaping, any script, emoji, rich text and markdown | Fonts and glyph ranges you load yourself |
| Plots | Sparklines, bar and donut charts, a canvas | Excellent built-in plotting (ImPlot) |
| Desktop features | Menus, shortcuts, multi-window, docks, code editor | Docking and viewports from ImGui |
| Designer, hot reload | Pyzed Design, pyzed dev |
– |
| Accessibility | Keyboard; no screen readers yet | No screen readers |
The same counter
Section titled “The same counter”"""Reference app: a counter with -, + and Reset."""
import pyzed as pzfrom pyzed import ui
class Counter(pz.App): title = "Counter" size = (320, 200)
def __init__(self): self.count = 0
def add(self, step): self.count += step
def view(self): return pz.center(pz.column([ ui.heading(str(self.count)), pz.row([ ui.button(icon="minus", on_press=lambda: self.add(-1)), ui.button(icon="plus", on_press=lambda: self.add(1), variant="solid"), ui.button("Reset", lambda: setattr(self, "count", 0), variant="ghost"), ], spacing=8), ], spacing=16, align="center"))
pz.run(Counter)"""Reference app: a counter with -, + and Reset."""
import dearpygui.dearpygui as dpg
dpg.create_context()count = 0
def change(step): global count count = 0 if step is None else count + step dpg.set_value("count", str(count))
with dpg.window(tag="main"): dpg.add_text("0", tag="count") with dpg.group(horizontal=True): dpg.add_button(label="-", callback=lambda: change(-1)) dpg.add_button(label="+", callback=lambda: change(1)) dpg.add_button(label="Reset", callback=lambda: change(None))dpg.create_viewport(title="Counter", width=320, height=200)dpg.setup_dearpygui()dpg.show_viewport()dpg.set_primary_window("main", True)dpg.start_dearpygui()dpg.destroy_context()The same to-do list
Section titled “The same to-do list”"""Reference app: add tasks (button or Enter), tick them off, delete them, see how many are left."""
import pyzed as pzfrom pyzed import ui
class Todo(pz.App): title = "To-do" size = (420, 480)
def __init__(self): self.tasks = [] # [title, done] self.draft = ""
def add(self): if self.draft.strip(): self.tasks.append([self.draft.strip(), False]) self.draft = ""
def toggle(self, task, done): task[1] = done
def row(self, task): return pz.row([ ui.checkbox(task[1], lambda done: self.toggle(task, done)), ui.label(task[0], color="text_muted" if task[1] else "text", width="fill"), ui.icon_button("trash-2", lambda: self.tasks.remove(task)), ], spacing=8, align="center")
def view(self): left = sum(not done for _, done in self.tasks) return pz.column([ ui.heading(f"{left} left", level=3), pz.row([ ui.input(self.draft, lambda text: setattr(self, "draft", text), on_submit=self.add), ui.button("Add", self.add, variant="solid"), ], spacing=8), pz.scrollable(pz.column([self.row(t) for t in self.tasks], spacing=4), height="fill"), ], spacing=12, padding=16)
pz.run(Todo)"""Reference app: add tasks (button or Enter), tick them off, delete them, see how many are left."""
import dearpygui.dearpygui as dpg
dpg.create_context()tasks = [] # [title, done]
def refresh(): dpg.delete_item("list", children_only=True) for task in tasks: with dpg.group(horizontal=True, parent="list"): dpg.add_checkbox(label=task[0], default_value=task[1], callback=lambda s, value, t=task: (t.__setitem__(1, value), refresh())) dpg.add_button(label="Delete", callback=lambda s, a, t=task: (tasks.remove(t), refresh())) dpg.set_value("left", f"{sum(not done for _, done in tasks)} left")
def add(): text = dpg.get_value("entry").strip() if text: tasks.append([text, False]) dpg.set_value("entry", "") refresh()
with dpg.window(tag="main"): dpg.add_text("0 left", tag="left") with dpg.group(horizontal=True): dpg.add_input_text(tag="entry", width=300, on_enter=True, callback=add) dpg.add_button(label="Add", callback=add) dpg.add_child_window(tag="list")dpg.create_viewport(title="To-do", width=420, height=480)dpg.setup_dearpygui()dpg.show_viewport()dpg.set_primary_window("main", True)dpg.start_dearpygui()dpg.destroy_context()Measured
Section titled “Measured”Medians from the benchmarks (Linux, no GPU: both render through Mesa’s software drivers).
| Measurement (lower is better in every row) | Pyzed 1.2.0 | Dear PyGui 2.3.1 |
|---|---|---|
| Import the library | 35 ms | 17 ms |
| First frame, 10 rows | 165 ms | 133 ms |
| First frame, 1,000 rows | 243 ms | 152 ms |
| Memory (RSS), 10 rows | 151 MB | 123 MB |
| Memory (RSS), 1,000 rows | 161 MB | 125 MB |
| Update 1,000 rows | 18 ms | 6.6 ms |
| Lines: counter | 19 lines | 19 lines |
| Lines: to-do list | 31 lines | 29 lines |
From Dear PyGui concepts to Pyzed
Section titled “From Dear PyGui concepts to Pyzed”| Dear PyGui | Pyzed |
|---|---|
create_context, create_viewport, start_dearpygui |
pz.run(MyApp) |
with dpg.window(...) |
the root returned by view() |
dpg.add_text(tag="x") + dpg.set_value("x", ...) |
ui.label(self.x): change self.x |
callback=fn |
on_press=fn |
dpg.group(horizontal=True) |
pz.row |
dpg.child_window |
pz.scrollable, ui.card, ui.panel |
dpg.theme() + bind_item_theme |
themes and styles |
dpg.add_plot |
ui.bar_chart, ui.sparkline, or pz.canvas for custom drawing |
When to choose which
Section titled “When to choose which”- Choose Dear PyGui for real-time plots, node editors, instrument panels and debug tools where the ImGui look is fine.
- Choose Pyzed for end-user apps: forms, lists, editors and dashboards that should look polished, with proper text, a designer, hot reload and packaging.