Skip to main content

f32nodes

PyPI Python Versions License CI

See every wire of your Python dataflow graph live.

Write nodes as plain Python classes, wire them in a YAML file, and f32nodes runs the graph in real time and draws a live gauge, waveform or heatmap for every port. No UI code needed.

Wavefields demo

Not a drag-and-drop editor. The graph is defined in code and YAML; the window is a live inspector where you can move nodes around and watch every signal.

Hello world

Two nodes: a sine source and a trace that keeps the last 200 samples. See demos/demo1 for a fully commented version.

nodes.py

import math, time
import numpy as np
from f32nodes.core import Node


class Sine(Node):
    def define_config(self):
        return {"hz": 0.5}

    def setup(self):
        self.t0 = time.perf_counter()

    def define_ports(self):
        self.add_output_port("out", shape=(), min_val=-1.0, max_val=1.0)  # scalar -> gauge

    def compute(self):
        t = time.perf_counter() - self.t0
        self.write_output("out", np.float32(math.sin(math.tau * self.config["hz"] * t)))


class Trace(Node):
    def define_config(self):
        return {}

    def setup(self):
        self.history = np.zeros(200, dtype=np.float32)

    def define_ports(self):
        self.add_input_port("in", shape=(), min_val=-1.0, max_val=1.0)
        self.add_output_port("history", shape=(200,), min_val=-1.0, max_val=1.0)  # 1D -> waveform

    def compute(self):
        self.history = np.roll(self.history, -1)
        self.history[-1] = self.read_input("in")
        self.write_output("history", self.history)

graph.yaml

paths:
  my: "nodes"

nodes:
  sine:
    type: my.Sine
    config: {hz: 0.5}
  trace:
    type: my.Trace

connections:
  - from: [sine, "out"]
    to: [trace, "in"]

main.py

from f32nodes import Runner

Runner("graph.yaml").start_app()

Run pip install f32nodes && python main.py.

Overview

Core Features

  • Python-native nodes: each node is a plain Python subclass representing one step of computation. Nodes declare typed ports and exchange numpy.float32 tensors.
  • YAML graph spec: node instances, configs, and connections sit in a YAML file; the loader resolves import prefixes relative to that file and wires ports automatically.
  • Strict graph & port contracts: preflight rejects unconnected nodes plus shape/range/cycle errors, enforces a single connected DAG, and port writes continue to enforce dtype, shape, and limits during execution.
  • Automatic visuals: the port contracts select a renderer per output shape (gauge, waveform, heatmap or RGBA texture), so nodes contain no UI code. Normalization happens in the renderer only.
  • Low-overhead UI: the PyQt graph view avoids per-frame allocations so rendering stays light next to the runtime.
  • Runtime instrumentation: the runner targets a configurable FPS, records backend/GUI/frame timings, samples per-node costs, and flags when the schedule drifts.
  • Persistent layout: the PyQt6 view stores node positions and viewport state per graph file so the workspace survives restarts.

Visualization Semantics

Renderer-only normalization: visual widgets resample or scale data for display, but the numpy buffers on ports stay untouched.

  • Scalar ports (shape == ()) render as bar gauges between declared bounds.
  • 1D ports (shape == (N,)) render as waveforms after resampling to viewport width.
  • 2D ports (shape == (H, W)) appear as grayscale heatmaps.
  • RGBA ports (shape == (H, W, 4)) display as color textures.

Scope Boundaries

  • No bundled node library; domain-specific nodes live alongside each project.
  • Graph execution is single-threaded within one Python process. Nodes may spawn their own threads, but the runtime does not orchestrate multi-threaded or distributed scheduling.
  • Ports standardize on numpy.float32 scalars and tensors for consistent interoperability; other dtypes require conversion at graph edges.
  • The runner provides best-effort real-time: it reports drift and timings but cannot enforce hard deadlines, and overall throughput is ultimately limited by Python/PyQt rather than native C++ speeds.

Getting Started

Install

Requirements: Python >=3.12, pip 23+, and a working Qt/OpenGL stack (installed automatically through PyQt6 on most platforms).

Install from PyPI:

pip install f32nodes

Every demo uses the same setup workflow; from the repo root:

cd demos/<demo_name>
python3 -m venv .venv; source .venv/bin/activate
pip install -r requirements.txt
python3 main.py

Demo 1 – Amplitude Modulation

A low-frequency scalar modulates a waveform generator. The entry point for learning the node API. All files in this demo are heavily commented to illustrate the full flow.

  • nodes.py – defines the modulator and carrier nodes.
  • graph.yaml – initializes & configures nodes, then connects the graph.
  • main.py – loads and runs the graph.

Demo 1 screenshot

Demo 2 – Wavefields

Coupled oscillators drive a drifting 2D height map, while the display node remixes the field into density, height, and a stylized RGBA texture.

Demo 2 screenshot

Demo 3 – Audio Nodes

Streams the bundled spectral_fx.wav, computes octave-band energy plus RMS, and drives an AudioVisualizer node whose three abstract controls (“background change”, “rectangle intensity”, “delay effect”) accept any scalar signal you patch into them. soundfile is required for decoding; sounddevice enables optional playback (toggle via enable_playback).

Demo 3 screenshot

Development

  • Tests: run pytest.

  • Linting: run ruff check ..

  • Packaging: the project ships with a Poetry pyproject.toml; use poetry install if you prefer Poetry over raw pip.

  • Editable install:

    python3 -m venv .venv
    source .venv/bin/activate
    pip install -U pip
    pip install -e .
    

License & Support

Licensed under the Apache License 2.0. Support is best effort; please open an issue on GitHub and I’ll respond as time allows.

  • Ryven — visual scripting environment for Python that emphasises interactive, dynamically typed nodes within a Qt interface.
  • PyFlow — general-purpose visual scripting system modelled after Unreal’s Blueprints, featuring a plug-in architecture and broad node catalog.
  • Nodezator — node-based Pygame application that streamlines prototyping workflows for games and creative coding projects.

Metadata

Release files for f32nodes 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for f32nodes 0.1.4
File Size Uploaded
f32nodes-0.1.4.tar.gz 24.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for f32nodes 0.1.4
File Interpreter ABI Platform
f32nodes-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 47.1 kB

Release files / f32nodes-0.1.4.tar.gz

Download URL f32nodes-0.1.4.tar.gz
Size 24.3 kB
Tags Source
SHA-256 checksum
How to use checksums
2595062138c6c79c322d2d83df86c3218eb2c5ad492bf47329051eecdc6d2dd4
BLAKE2b-256 checksum
How to use checksums
25a39e62841d314db1d2d844e5ff66fc1b67e98060c9d2605181f15c643cf8db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / f32nodes-0.1.4-py3-none-any.whl

Download URL f32nodes-0.1.4-py3-none-any.whl
Size 22.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fb40046c1553856ef140697b4168569c376f77d2564bee56d0e0d96d1a52b422
BLAKE2b-256 checksum
How to use checksums
e4477683a1f67eb860c6af9f6f13a4dcc63df7f4295ee8921ade01cbe5cd8ba5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page