Skip to main content

spaday-perspective

Perspective for spaday

Build Status codecov License PyPI

Overview

spaday-perspective moves the existing PerspectivePanel integration out of spaday core. Its self-contained <perspective-panel> bundle includes Perspective's client, viewer, workspace, datagrid, themes, and viewer WASM.

Interactive example

This complete app serves a live Perspective table. Add trade streams a new row into the grid, the select switches between flat and grouped layouts, and the checkbox changes the viewer theme.

import perspective
from perspective.handlers.starlette import PerspectiveStarletteHandler
from starlette.responses import JSONResponse
from starlette.routing import Route, WebSocketRoute
from starlette.websockets import WebSocket

from spaday import CallEndpoint, cond, element, eq, field, obj
from spaday.backends.starlette import serve
from spaday_perspective import PerspectivePanel

server = perspective.Server()
client = server.new_local_client()
trades = client.table(
    [
        {"id": 1, "symbol": "AAPL", "side": "buy", "price": 211.10},
        {"id": 2, "symbol": "MSFT", "side": "sell", "price": 503.02},
    ],
    name="trades",
)
next_id = 2


async def add_trade(_request):
    global next_id
    next_id += 1
    trades.update(
        [
            {
                "id": next_id,
                "symbol": "AAPL" if next_id % 2 else "MSFT",
                "side": "buy" if next_id % 2 else "sell",
                "price": 210 + next_id,
            }
        ]
    )
    return JSONResponse({"id": next_id})


async def perspective_socket(websocket: WebSocket):
    await PerspectiveStarletteHandler(perspective_server=server, websocket=websocket).run()


def layout(*, grouped=False):
    viewer = {"table": "trades", "plugin": "Datagrid", "columns": ["symbol", "side", "price"]}
    if grouped:
        viewer.update({"group_by": ["symbol"], "columns": ["price"], "aggregates": {"price": "avg"}})
    return {
        "sizes": [1],
        "detail": {"main": {"type": "tab-area", "widgets": ["trades"], "currentIndex": 0}},
        "master": {"sizes": [], "widgets": []},
        "mode": "globalFilters",
        "viewers": {"trades": viewer},
    }


panel = (
    PerspectivePanel()
    .compute("theme", cond(field("dark"), "dark", "light"))
    .compute(
        "config",
        obj(
            {
                "ws_url": "/perspective",
                "tables": ["trades"],
                "layout": cond(eq(field("view"), "grouped"), layout(grouped=True), layout()),
            }
        ),
    )
    .style(display="block", height="70vh", margin_top="1rem")
)

view = element("select").bind("value", "view", mode="two-way").child(
    element("option", "Blotter", value="blotter"),
    element("option", "Average by symbol", value="grouped"),
)
dark = element("input", type="checkbox").bind("checked", "dark", mode="two-way")
page = (
    element("main")
    .style(margin="1rem", font_family="system-ui")
    .child(element("button").text("Add trade").on("click", CallEndpoint("POST", "/api/trades")))
    .child(view)
    .child(element("label").child(dark, " Dark theme"))
    .child(panel)
)

app = serve(
    page,
    packages=["perspective"],
    store={"view": "blotter", "dark": False},
    routes=[
        Route("/api/trades", add_trade, methods=["POST"]),
        WebSocketRoute("/perspective", perspective_socket),
    ],
)

Save this as app.py, then run pip install spaday-perspective perspective-python starlette uvicorn and uvicorn app:app. Open http://127.0.0.1:8000.

This keeps Perspective's bulk data on its native websocket. A spaday/transports model only needs to carry the small serializable connection/layout config. Replacing config reconnects when ws_url changes and restores changed layouts; theme accepts light, dark, or a Perspective theme name.

Installing this project registers the perspective entry point with spaday. The equivalent explicit forms are packages=[spaday_perspective.package] and packages=["spaday_perspective:package"].

[!NOTE] This library was generated using copier from the Base Python Project Template repository.

Download files

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

Source Distribution

spaday_perspective-0.1.0.tar.gz (2.0 MB view details)

Uploaded Source

Built Distribution

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

spaday_perspective-0.1.0-py3-none-any.whl (2.0 MB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: spaday_perspective-0.1.0.tar.gz
  • Upload date:
  • Size: 2.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for spaday_perspective-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c6b14eca5012d13c53335a56e198c7b0d0e8821c35abd89308bb7a36afec3d16
MD5 c40d3f9bc3ee05f99db26bd943fd14e3
BLAKE2b-256 d211974b4e6ae49fcef15b2d1d7751c9622c57c65efb7e83bb66b0ba44fa41a5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for spaday_perspective-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c2071a8361d3d3857559da5819348041dc785541206c9ac2ca7d8f40d149d0ea
MD5 483d0a12d4b78de92f986967a9b05818
BLAKE2b-256 27f6345814ff44f49ec50be4e9556bb57d6bd9e3c114bd18b655e5b62d27a953

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 Sentry Error logging StatusPage Status page