--- myst: html_meta: description: "Upload, stream, organize and read back data with the Nominal Python Client." --- # Python quickstart {.lead} A simple quickstart to show some basic features of `NominalClient`. To run this code locally, you need nominal-client [installed](/guides/install.md) and your [API keys](/guides/api-keys-setup.md) setup. ## Connect The first step is to open a connection to nominal through the NominalClient. ```python 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: ```python 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: ```python 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](/guides/datasets/overview.md). ## 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: ```python 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](/guides/streaming/overview.md) 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. ```python 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 more about [runs](/guides/runs.md) and [events](/guides/events.md). ## Read data back `datasource_to_dataframe` downloads channels into a pandas DataFrame indexed by timestamp. ```python 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](/guides/datasets/export-data.md). ## Clean up Archiving hides the objects from views and searches. It doesn't delete the data. ```python event.archive() run.archive() dataset.archive() asset.archive() ``` ## Next steps * [Upload and stream tutorial](/guides/longstart.md): a longer walkthrough with a racecar dataset and live workbooks. * [Data integration tutorial](/guides/data-integration-tutorial.md): connect your own data sources. * [Examples](/examples/index.md): full, runnable scripts. * [SDK reference](/sdk/index.md): every class and function.