Skip to main content

Python WebSocket client for the Loom Genome Browser

Project description

loom-client

Python WebSocket client for the Loom Genome Browser. Provides a fully async, typed interface for programmatically controlling a running Loom instance -- navigating loci, managing tracks and regions of interest, exporting views, and subscribing to browser events.

Installation

pip install loom-client

Or install from source:

git clone https://github.com/riyavsinha/loom-client.git
cd loom-client
pip install -e .

Requires Python >= 3.11.

Quick start

Option 1: Connect to a Loom instance

Use this when your code initiates the WebSocket connection to a running Loom server.

import asyncio
from loom_client import LoomClient

async def main():
    client = LoomClient("ws://localhost:8080")
    await client.connect()

    # Get current browser state
    state = await client.get_browser_state()
    print(state.locus_string)   # e.g. "chr1:1,000-2,000"
    print(state.zoom_level)     # e.g. ZoomLevel.GENE

    # Navigate to a locus
    await client.navigate(locus="chr17:7565097-7590856")  # TP53

    # Zoom out 2x
    await client.navigate(zoom="out", factor=2.0)

    await client.close()

asyncio.run(main())

Option 2: Use an existing WebSocket connection

Use this when the WebSocket is already established — for example, a frontend-initiated connection handled by your backend, or when bridging through a proxy.

from loom_client import LoomClient

async def handle_connection(websocket):
    """Example: called by your WebSocket server when a client connects."""
    client = LoomClient.from_websocket(websocket)
    client.start_listening()

    state = await client.get_browser_state()
    print(state.locus_string)

    await client.close()

API reference

Connection

# Option 1: Initiate a new connection
client = LoomClient(url)   # Create client
await client.connect()     # Open WebSocket + start listener

# Option 2: Reuse an existing WebSocket
client = LoomClient.from_websocket(ws)  # Wrap existing connection
client.start_listening()                # Start listener

await client.close()       # Tear down

Commands

All command methods are async and return typed Pydantic models.

get_browser_state(record=None) -> ProjectedState

Returns the current viewport state including locus, zoom level, loaded tracks, and ROIs.

state = await client.get_browser_state()
for track in state.tracks:
    print(f"{track.name} ({track.type})")

navigate(locus=None, zoom=None, factor=None) -> bool

Move the viewport to a genomic locus or zoom in/out.

await client.navigate(locus="chr1:1000-2000")
await client.navigate(zoom="in", factor=3.0)

modify_tracks(actions) -> ModifyTracksResult

Add, remove, find, or update tracks in a single batch.

from loom_client import AddTrackAction, RemoveTrackAction, TrackSessionConfig, DataSourceConfig, WireTrackSelector

# Add a BigWig track
result = await client.modify_tracks([
    AddTrackAction(config=TrackSessionConfig(
        type="wig",
        name="H3K27ac",
        data_source=DataSourceConfig(
            type="bigwig",
            url="https://example.com/h3k27ac.bw",
        ),
    ))
])

# Remove by name pattern
result = await client.modify_tracks([
    RemoveTrackAction(selector=WireTrackSelector(name_regex="H3K.*"))
])

query_features(track_id, summarize=None) -> QueryFeaturesResult

Query features for a loaded track.

result = await client.query_features("track-id-123", summarize=True)
print(result.feature_count)

set_layout(tracks, locus=None) -> SetLayoutResult

Replace the entire track layout at once.

result = await client.set_layout(
    tracks=[
        TrackSessionConfig(type="ruler"),
        TrackSessionConfig(type="sequence"),
        TrackSessionConfig(
            type="annotation",
            name="GENCODE",
            data_source=DataSourceConfig(type="gencode", genome="hg38"),
        ),
    ],
    locus="chr1:1000-5000",
)

export_view(format, width=None) -> str | SessionConfig

Export the current view as SVG, PNG (returned as strings), or a session config object.

svg = await client.export_view("svg", width=1200)
session = await client.export_view("session")  # returns SessionConfig

manage_rois(action) -> ROI result

Manage regions of interest. The action type determines the operation.

from loom_client import AddROIAction, ROI, ListROIAction, FindROIAtLocusAction

# Add a region of interest
result = await client.manage_rois(AddROIAction(
    roi=ROI(id="roi-1", chr="chr17", start=7565097, end=7590856,
            name="TP53", color="rgba(255,0,0,0.3)"),
    set_name="Genes of interest",
))

# List all ROIs
result = await client.manage_rois(ListROIAction())

# Find ROIs overlapping a locus
result = await client.manage_rois(
    FindROIAtLocusAction(chr="chr17", start=7500000, end=7600000)
)

subscribe_events(events) -> SubscribeEventsResult

Subscribe to server-pushed events. Use ["*"] for all events or [] to unsubscribe.

await client.subscribe_events(["locuschange", "trackadded", "dataloaded"])

Event handling

Register callbacks for browser events:

def on_locus_change(data):
    locus = data["locus"]
    print(f"Moved to {locus['chr']}:{locus['start']}-{locus['end']}")

client.on("locuschange", on_locus_change)

# Wildcard handler receives (event_name, data)
client.on("*", lambda name, data: print(f"Event: {name}"))

# Unregister
client.off("locuschange", on_locus_change)

Available events: locuschange, trackadded, trackremoved, dataloaded, dataerror, rendererror, trackclick, trackhover, trackcontextmenu, trackorderchanged, roiadded, roiremoved, roichanged, roiclick, roicontextmenu

Error handling

Server errors raise CommandException:

from loom_client import CommandException

try:
    await client.navigate(locus="invalid")
except CommandException as e:
    print(e.code, e.message)

Development

pip install -e ".[dev]"
pytest

License

MIT

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

loom_client-0.0.3.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

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

loom_client-0.0.3-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file loom_client-0.0.3.tar.gz.

File metadata

  • Download URL: loom_client-0.0.3.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for loom_client-0.0.3.tar.gz
Algorithm Hash digest
SHA256 d66d2c22d2f7b6bf00edb61d6017af65e4d3c7f5fdf84b94ce00c4d7b0d200bd
MD5 4a14eb62b68ef9fa8dc084574e34316e
BLAKE2b-256 8ed96c4ceea14dc4432b747b9e3c133980eebbe4cbcd3355941add340866be98

See more details on using hashes here.

File details

Details for the file loom_client-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: loom_client-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for loom_client-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 13e3f642d8beb789ac83df1ee9c6bf84c173e07b963517603e50ec17d4d60261
MD5 6acfe57488301109f9e4b9c694bf7706
BLAKE2b-256 45e7dac5a940bec5f76d6c1d7990d5eba8f18cbf5e6350c4f6ef3328367349b5

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