Skip to main content

Build interactive data web apps in pure Python

Project description

spyre2

Build interactive data web apps in pure Python — no HTML, CSS, or JavaScript required.

Spyre2 is a ground-up rewrite of spyre using a modern stack: FastAPI, Alpine.js, and native support for matplotlib, Plotly, and Altair.


Install

pip install spyre2
pip install spyre2[matplotlib]   # + matplotlib
pip install spyre2[plotly]        # + plotly
pip install spyre2[all]           # everything

Quickstart

import numpy as np
import matplotlib.pyplot as plt
import spyre2

class SineApp(spyre2.App):
    title = "Sine Wave"

    inputs = [
        spyre2.Slider("frequency", label="Frequency", min=1, max=20, default=5),
        spyre2.Dropdown("color", label="Color",
                        options=["steelblue", "crimson", "seagreen"]),
    ]

    outputs = [
        spyre2.Plot("sine_plot"),
    ]

    def sine_plot(self, frequency, color):
        fig, ax = plt.subplots(figsize=(8, 4))
        x = np.linspace(0, 2 * np.pi, 500)
        ax.plot(x, np.sin(frequency * x), color=color)
        return fig

SineApp().launch()

Open http://127.0.0.1:8000.


Inputs

Class Description
Slider(id, min, max, step, default) Numeric range slider
Dropdown(id, options, default) Select dropdown
RadioButtons(id, options, default) Radio button group
CheckboxGroup(id, options, default) Multi-select checkboxes
TextInput(id, default, placeholder) Free-text input
FileUpload(id, accept) File picker

All inputs accept a label keyword argument. If omitted, the label is inferred from the id.


Outputs

Class Handler return type
Plot(id) matplotlib.figure.Figure or plotly.Figure or altair.Chart
Table(id) pandas.DataFrame
HTML(id) str (HTML)
Download(id) (filename: str, content: str | bytes)

The handler method name must match the output id:

outputs = [spyre2.Plot("my_plot")]

def my_plot(self, **kwargs):   # method name = output id
    ...
    return fig

Layouts

Sidebar (default)

Controls on the left, outputs stacked on the right. No configuration needed.

Grid

from spyre2 import Layout

class MyApp(spyre2.App):
    layout = Layout.grid([
        ["controls",  "controls"  ],
        ["plot_a",    "plot_b"    ],
        ["big_table", "big_table" ],
    ])

Repeat an ID across adjacent cells to span columns. "controls" is a reserved name for the input panel.

Tabs

layout = Layout.tabs({
    "Overview": ["trend_plot"],
    "Detail":   ["data_table", "bar_chart"],
})

Multiple chart libraries

The chart library is detected automatically from the return type — no configuration needed.

# matplotlib
def my_plot(self, x):
    fig, ax = plt.subplots()
    ax.plot(...)
    return fig              # → rendered as SVG

# Plotly
import plotly.express as px
def my_plot(self, x):
    return px.scatter(df, x="a", y="b")   # → rendered via Plotly.js

# Altair
import altair as alt
def my_plot(self, x):
    return alt.Chart(df).mark_line()...   # → rendered via Vega-Embed

Jupyter notebooks

app.launch() detects when it's running inside a Jupyter kernel and automatically starts the server in a background thread and displays an inline IFrame.

SineApp().launch(port=8765)   # displays inline in the notebook

Migrating from spyre v1

Use the included CLI tool to mechanically convert a v1 app:

spyre2-migrate myapp.py              # preview conversion
spyre2-migrate myapp.py -o new.py    # write to new file
spyre2-migrate myapp.py --in-place   # overwrite (creates .bak backup)

The tool converts imports, inputs/outputs list-of-dicts, and renames getPlot/getTable etc., leaving # TODO comments where manual cleanup is needed.

What changes:

spyre v1 spyre2
from spyre import server import spyre2
class App(server.App) class App(spyre2.App)
inputs = [{"type": "slider", "key": "x", ...}] inputs = [spyre2.Slider("x", ...)]
def getPlot(self, params): x = params["freq"] def my_plot(self, freq):
CherryPy on port 9093 uvicorn on port 8000

For apps that can't be fully migrated yet, spyre2.compat.App accepts the old dict-based syntax (deprecated, will be removed in a future release).


Examples

File Demonstrates
examples/sine_example.py Sidebar layout, matplotlib, slider + dropdown
examples/grid_example.py Grid layout, matplotlib, multiple outputs + table
examples/plotly_example.py Tabs layout, Plotly, scatter + histogram

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spyre2-0.1.0.tar.gz (108.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spyre2-0.1.0-py3-none-any.whl (42.0 kB view details)

Uploaded Python 3

File details

Details for the file spyre2-0.1.0.tar.gz.

File metadata

  • Download URL: spyre2-0.1.0.tar.gz
  • Upload date:
  • Size: 108.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for spyre2-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f309f5ebaa55f6b2465cd06148e5ba0423abc87effe905bedc9c801231f98514
MD5 60f482ce64d7f99213942398e3537735
BLAKE2b-256 9323631bccdc7d84fb2ab72b30984cafba7ac9bb2258bfc4fe3c87e2adfc9804

See more details on using hashes here.

File details

Details for the file spyre2-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: spyre2-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 42.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for spyre2-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ec0925221d63f3115f3a11a7b27ddee18888a7def5f0aea1b0a7570eda5f10cf
MD5 c17d4ec4e0fefcf713a1b5628b2b6d9f
BLAKE2b-256 d92d4fdb6bf8cee4a086f7201434e645a17ee75fb718582ca99886b0b24e9d1c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page