Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 62 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,70 @@
# Atomscale Python SDK
<p align="center">
<img src="docs/_static/AtomscaleLogoFull.png" alt="Atomscale" width="300">
</p>

[![Testing](https://github.com/atomscale-ai/sdk/workflows/Testing/badge.svg)](https://github.com/atomscale-ai/sdk/actions?query=workflow:"Testing")
[![GitHub tag](https://img.shields.io/github/tag/atomscale-ai/sdk?include_prereleases=&sort=semver&color=blue)](https://github.com/atomscale-ai/sdk/releases/)
![Python](https://img.shields.io/badge/Python-3.10+-blue.svg?logo=python&logoColor=white)
[![License](https://img.shields.io/badge/License-GPLv3-blue)](#license)
<h1 align="center">Python SDK</h1>

[![view - Documentation](https://img.shields.io/badge/view-Documentation-blue?style=for-the-badge)](https://atomscale-ai.github.io/sdk/)
<p align="center">
<a href="https://github.com/atomscale-ai/sdk/actions/workflows/testing.yml?query=branch%3Amain"><img src="https://github.com/atomscale-ai/sdk/actions/workflows/testing.yml/badge.svg?branch=main" alt="Testing"></a>
<a href="https://github.com/atomscale-ai/sdk/releases/"><img src="https://img.shields.io/github/tag/atomscale-ai/sdk?include_prereleases=&sort=semver&color=blue" alt="GitHub tag"></a>
<img src="https://img.shields.io/badge/Python-3.10+-blue.svg?logo=python&logoColor=white" alt="Python">
<a href="#license"><img src="https://img.shields.io/badge/License-MPL_2.0-blue" alt="License"></a>
</p>

## Install
<p align="center">
<a href="https://atomscale-ai.github.io/sdk/"><img src="https://img.shields.io/badge/view-Documentation-blue?style=for-the-badge" alt="Documentation"></a>
</p>

---

The official Python SDK for the [Atomscale](https://www.atomscale.ai) platform. Upload RHEED videos, stream live data, search the catalogue, and retrieve analysis results programmatically.

## Features

- **Unified Client** – Single interface for uploads, search, and downloads
- **Live Streaming** – Push or pull RHEED frames in real-time
- **Flexible Search** – Filter by keywords, data type, status, or time bounds
- **Rich Results** – Access timeseries, diffraction graphs, and processed videos
- **Polling Utilities** – Sync, async, and threaded options for monitoring updates

## Installation

```bash
pip install atomscale
```

> The package was renamed from `atomicds`. Importing `atomicds` (or installing
> `atomicds`) still works via a thin shim but emits a `DeprecationWarning`.
> **Note:** The package was renamed from `atomicds`. Importing `atomicds` still works but emits a `DeprecationWarning`.

## Quick Start

```python
from atomscale import Client

# Create a client (reads AS_API_KEY from environment)
client = Client()

# Upload files
client.upload(files=["rheed_video.mp4"])

# Search the catalogue
results = client.search(keywords=["GaN"], status="success")

# Fetch analysis results
items = client.get(results["Data ID"].to_list())
for item in items:
print(item.timeseries_data.tail())
```

## Documentation

Full documentation is available at **[atomscale-ai.github.io/sdk](https://atomscale-ai.github.io/sdk/)**.

- [Quickstart Guide](https://atomscale-ai.github.io/sdk/guides/quickstart.html)
- [Upload Data](https://atomscale-ai.github.io/sdk/guides/upload-data.html)
- [Search the Catalogue](https://atomscale-ai.github.io/sdk/guides/search-data.html)
- [Stream RHEED Video](https://atomscale-ai.github.io/sdk/guides/stream-rheed.html)
- [API Reference](https://atomscale-ai.github.io/sdk/modules.html)

## License

This project is licensed under the [Mozilla Public License 2.0](LICENSE).
Binary file added docs/_static/AtomscaleLogoFull.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* Override hardcoded logo dimensions */
img[alt="Logo"] {
height: 48px !important;
width: auto !important;
max-height: none !important;
}

/* Target the header/nav area logo specifically */
header img[alt="Logo"],
nav img[alt="Logo"],
a img[alt="Logo"] {
height: 25px !important;
width: auto !important;
position: relative;
top: -5px;
}

/* Force badges to display inline horizontally */
p > a.reference.external,
p > img {
display: inline !important;
margin-right: 4px;
}

p > a.reference.external > img {
display: inline !important;
vertical-align: middle;
}

/* Reduce space between h1 and badges, add space below badges */
section > h1 {
margin-bottom: 0.25rem !important;
}

section > p:first-of-type {
margin-top: 0 !important;
margin-bottom: 1.5rem !important;
}
38 changes: 11 additions & 27 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,37 +72,21 @@
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "alabaster"
# html_static_path = ['_static']
html_theme = "sphinxawesome_theme"

html_static_path = ["_static"]
html_css_files = ["custom.css"]
html_logo = "_static/AtomscaleLogoFull.png"
html_title = "Python SDK"

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
"github_button": True,
"github_type": "star&v=2",
"github_user": "atomic-data-sciences",
"github_repo": "api-client",
"github_banner": True,
"description": "Python SDK",
"show_breadcrumbs": True,
"show_prev_next": True,
"logo_light": "_static/AtomscaleLogoFull.png",
"logo_dark": "_static/AtomscaleLogoFull.png",
}

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
html_sidebars = {
"**": [
"about.html",
"navigation.html",
"searchbox.html",
]
}
html_permalinks_icon = "<span>#</span>"

# -- Options for HTMLHelp output ---------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions docs/guides/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ single workflow so you can jump straight to what you need.
inspect-results
stream-rheed
poll-timeseries
poll-trajectory
35 changes: 35 additions & 0 deletions docs/guides/inspect-results.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Each item in ``analysed`` is a subclass of
:class:`atomscale.results.RHEEDVideoResult` or
:class:`atomscale.results.RHEEDImageResult`, depending on the source data.

.. note::

The :meth:`get` call fetches metadata and analysis artefacts for each ID.
For large result sets, consider batching or filtering first.

Inspect time series data
------------------------

Expand All @@ -34,6 +39,21 @@ Inspect time series data
The timeseries frame contains specular intensity, strain metrics, cluster IDs,
and other summary features for every frame in the video.

.. list-table:: Common timeseries columns
:header-rows: 1
:widths: 30 70

* - Column
- Description
* - ``timestamp``
- Frame timestamp in seconds
* - ``specular_intensity``
- Specular spot brightness
* - ``strain``
- Computed strain metric
* - ``cluster_id``
- Pattern cluster assignment

Work with extracted frames
--------------------------

Expand All @@ -47,6 +67,11 @@ Work with extracted frames
``pattern_graph`` exposes the detected diffraction network as a NetworkX graph,
while :meth:`get_pattern_dataframe` returns a tidy table describing each spot.

.. tip::

Use ``figure.savefig("snapshot.png")`` to export plots for reports or
publications.

Download processed videos
-------------------------

Expand All @@ -58,3 +83,13 @@ Download processed videos
)

The files are saved as MP4 (one per data ID) and mirror what you see in the UI.

.. caution::

Downloaded videos can be large. Ensure you have sufficient disk space and
consider filtering to only the IDs you need.

.. seealso::

- :doc:`poll-timeseries` – Poll for live timeseries updates
- :doc:`poll-trajectory` – Poll similarity trajectory data
31 changes: 27 additions & 4 deletions docs/guides/poll-timeseries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ analysis. This guide summarises the four helper entry points in
- **Async background task** with :func:`start_polling_task` – fire-and-forget
inside an asyncio application.

.. tip::

For similarity trajectory data that tracks structure-property relationships,
see :doc:`poll-trajectory` instead. That API auto-stops when the trajectory
completes.

Shared setup
------------

Expand Down Expand Up @@ -41,9 +47,7 @@ Synchronous polling

Loop over :func:`iter_poll` to fetch fresh rows on a fixed cadence. The helper
waits ``interval`` seconds between polls so a simple ``for`` loop is enough to
keep the script going. Use ``distinct_by`` to avoid duplicates,
``max_polls`` to stop automatically, and ``fire_immediately=False`` to skip the
first immediate request if you only want timed polls.
keep the script going.

.. code-block:: python

Expand All @@ -61,13 +65,19 @@ first immediate request if you only want timed polls.
print(f"Poll {idx}: latest timestamp -> {latest_timestamp(result)}")
print(result.tail())

.. note::

The iterator uses **drift-corrected scheduling** to maintain accurate timing
even when individual polls are slow. Use ``distinct_by`` to avoid processing
duplicate data, and ``fire_immediately=False`` to skip the initial poll.

Background thread helper
------------------------

Use :func:`start_polling_thread` when you want updates but cannot block the
main thread (for example, inside a GUI or acquisition loop). The helper spawns
a daemon thread, starts polling immediately, and forwards each update to your
callback. Call ``stop_event.set()`` to shut it down cleanly.
callback.

.. code-block:: python

Expand All @@ -91,6 +101,11 @@ callback. Call ``stop_event.set()`` to shut it down cleanly.

# Call stop_event.set() to terminate early.

.. caution::

The callback runs in the polling thread, not the main thread. If you need to
update UI elements, use thread-safe mechanisms (e.g., ``queue.Queue``).

Async utilities
---------------

Expand All @@ -101,6 +116,8 @@ Two helpers integrate with asyncio:
* :func:`start_polling_task` creates a background task that awaits the poller
in parallel and invokes an (optional) async handler for each result.

**Async iterator**

.. code-block:: python

import asyncio
Expand All @@ -121,6 +138,8 @@ Two helpers integrate with asyncio:

asyncio.run(stream_updates())

**Background task**

.. code-block:: python

async def handle_async(result):
Expand All @@ -141,3 +160,7 @@ Two helpers integrate with asyncio:


asyncio.run(main())

.. tip::

Cancel the task with ``task.cancel()`` to stop polling early in async code.
Loading