Python quickstart#
A simple quickstart to show some basic features of NominalClient.
To run this code locally, you need nominal-client installed and your API keys setup.
Connect#
The first step is to open a connection to nominal through the NominalClient.
from nominal.core import NominalClient
client = NominalClient.from_profile("default") # replace if different
Upload Data#
Next, we synthesize some sample data and upload it to nominal. An asset represents the system you test, such as a vehicle or a test stand. Its datasets hold the channels you record.
Synthesize Data#
Generate one minute of sample engine data as a CSV:
import uuid
from datetime import datetime, timedelta, timezone
import numpy as np
import pandas as pd
# A unique ID keeps this run's asset separate from anyone else's.
run_id = uuid.uuid4().hex[:8]
start = datetime.now(timezone.utc) - timedelta(minutes=1)
t = np.arange(0, 60, 0.1) # 10 Hz for 60 seconds
pd.DataFrame({"timestamp": start.timestamp() + t,
"rpm": 3000 + 500 * np.sin(t / 5),
"coolant_temp_c": 80 + t / 6}
).to_csv("engine.csv", index=False)
Upload#
Create the asset and a dataset on it, then upload the file:
asset = client.get_or_create_asset_by_properties(
{"serial": f"QS-{run_id}"}, # properties identify the physical system
name=f"Quickstart engine {run_id}",
)
dataset = asset.get_or_create_dataset("engine")
file = dataset.add_tabular_data("engine.csv", timestamp_column="timestamp", timestamp_type="epoch_seconds")
file.poll_until_ingestion_completed()
print(asset.nominal_url)
Open the printed URL to see the asset and its engine dataset in Nominal.
Every other column in the CSV becomes a channel: rpm and coolant_temp_c.
For other formats, see Datasets.
Stream live data#
A write stream sends values as your code produces them, batching them in the background. This block streams 10 seconds of values to the same dataset:
import time
with dataset.get_write_stream() as stream: # the stream flushes when the block exits
for _ in range(100):
now = datetime.now(timezone.utc)
stream.enqueue("rpm", now, 3000 + 200 * np.random.randn())
stream.enqueue("oil_pressure_kpa", now, 300 + 5 * np.random.randn())
time.sleep(0.1)
To watch values arrive, open a workbook on the asset and click Go Live. See Streaming for the full set of options.
Mark a run and an event#
A run names a span of time on an asset, such as one test. An event marks a moment or span inside it that a reviewer should see.
from nominal.core import EventType
end = datetime.now(timezone.utc)
run = asset.create_run(f"Quickstart run {run_id}", start=start, end=end)
event = asset.create_event(
"Coolant above 85 °C",
EventType.FLAG,
start=start + timedelta(seconds=30),
duration=timedelta(seconds=30),
)
print(run.nominal_url)
Read data back#
datasource_to_dataframe downloads channels into a pandas DataFrame indexed by timestamp.
from nominal.thirdparty.pandas import datasource_to_dataframe
df = datasource_to_dataframe(dataset, channel_exact_match=["rpm"])
print(df.describe())
The result includes both the uploaded and the streamed rpm values.
To export to files or decimate long recordings, see Export data.
Clean up#
Archiving hides the objects from views and searches. It doesn’t delete the data.
event.archive()
run.archive()
dataset.archive()
asset.archive()
Next steps#
Upload and stream tutorial: a longer walkthrough with a racecar dataset and live workbooks.
Data integration tutorial: connect your own data sources.
Examples: full, runnable scripts.
SDK reference: every class and function.