Analysis Results#
Access the data extracted from your RHEED videos and images.
Fetch Results#
from atomscale import Client
client = Client()
# Search for data
search_results = client.search(keywords=["GaN"], status="success")
# Fetch analysis results
analysed = client.get(search_results["Data ID"].to_list())
Each item in analysed is a result object with properties for accessing
different types of analysis data.
Timeseries Data#
For RHEED videos, get frame-by-frame analysis:
video = analysed[0]
df = video.timeseries_data
print(df.columns)
print(df.tail())
Common columns:
Column |
Description |
|---|---|
|
Frame timestamp in seconds |
|
Specular spot brightness |
|
Computed strain metric |
|
Pattern cluster assignment |
Low-Level Features#
RHEED videos expose a larger set of low-level, per-region features (e.g.
area_0, eccentricity_0, fwhm_0_3) beyond the standard columns above.
Request them with get_rheed_timeseries(), which
returns a DataFrame indexed by ["Angle", "Frame Number"]:
df = client.get_rheed_timeseries(data_id, include_low_level_features=True)
print(df.filter(like="area").columns)
The low-level columns keep their raw backend names (they are not renamed).
Segmentation Masks#
Each featurized frame of a processed RHEED video carries a binary segmentation
mask of the diffraction pattern. Attach the masks to the timeseries — aligned on
the Frame Number axis, alongside any low-level features — with
include_masks:
from atomscale.results import decode_mask_rle
df = client.get_rheed_timeseries(
data_id,
include_low_level_features=True,
include_masks=True,
)
# Mask columns: mask_rle (COCO RLE string), mask_height, mask_width. Coverage
# is sparse -- frames without a mask are NA -- so drop those rows first.
row = df.dropna(subset=["mask_rle"]).iloc[0]
mask = decode_mask_rle(row["mask_rle"], row["mask_height"], row["mask_width"])
print(mask.shape) # (H, W) uint8, values 0/1
Fetch masks on their own — optionally decoded and keyed by absolute frame
number — with get_frame_masks():
masks = client.get_frame_masks(data_id, decode=True) # {frame_number: (H, W) array}
Sample-Level Results#
Some results are computed per physical sample rather than per data item —
rheed_quality and composition_metric are compiled from a sample’s
constituent RHEED videos into one series each. Fetch them with
get_physical_sample_timeseries():
ts = client.get_physical_sample_timeseries(
physical_sample_id, property_names=["rheed_quality"]
)
# Long form: one row per (property, sample-point). Reduce to a scalar yourself.
q = ts.loc[ts.property_name == "rheed_quality", "value"].dropna()
print(q.mean())
The frame is long (not wide) because distinct properties can have different
axes, so a wide join on real_time_seconds would mis-align them. value is
NaN for gaps; provenance columns (result_id, last_updated,
generating_dbos_workflow_id) travel alongside, and per-property
constituent_data_ids are in ts.attrs["constituent_data_ids"].
property_names filters client-side; omit it for all properties.
The same metrics are attached to get_physical_sample()
results as sample_metrics (pass include_sample_metrics=False to skip the
extra request):
sample = client.get_physical_sample(physical_sample_id)
print(sample.sample_metrics) # None if the sample has no computed metrics
Embedding Vectors#
The similarity pipeline persists Chronos embedding vectors for RHEED data — the
inputs to similarity matching, as opposed to the derived similarity-vs-time
trajectory. Fetch them with get_embeddings():
emb = client.get_embeddings(data_id, window_span=60.0, kind="window")
print(emb.vectors.shape) # (n_windows, dimension)
To find the RHEED data items most similar to a given one, run a
k-nearest-neighbour query over the embedding index with
query_rheed_embeddings():
neighbours = client.query_rheed_embeddings(data_id, top_k=10)
print(neighbours[["data_id", "similarity"]])
Extracted Frames#
Access snapshots extracted during analysis:
snapshot = video.snapshot_image_data[0]
# Get matplotlib figure
fig = snapshot.get_plot()
fig.savefig("snapshot.png")
# Get diffraction pattern as DataFrame
pattern_df = snapshot.get_pattern_dataframe()
# Get pattern as NetworkX graph
graph = snapshot.pattern_graph
Result Types#
The type of result object depends on the source data:
Data Type |
Result Class |
|---|---|
|
|
|
|
|
|
Batch Processing#
Process multiple results efficiently:
for item in analysed:
if hasattr(item, "timeseries_data"):
df = item.timeseries_data
avg_intensity = df["specular_intensity"].mean()
print(f"{item.data_id}: avg intensity = {avg_intensity:.2f}")