# Datasets

A dataset holds timestamped data as named channels, such as `altitude` or `temperature`.
Files you upload and points you stream add to the same dataset over time.

## Connect the client

This guide assumes you have [installed](https://dev.nominal.io/python/guides/install.md) the client and setup your [API keys](https://dev.nominal.io/python/guides/api-keys-setup.md).

```python
from nominal.core import NominalClient

client = NominalClient.from_profile("default")
```

## Create a dataset and upload a file

Create a dataset with [`create_dataset()`](https://dev.nominal.io/python/ref/generated/nominal.core.NominalClient.md#nominal.core.NominalClient.create_dataset "nominal.core.NominalClient.create_dataset"), or on an asset with [`get_or_create_dataset()`](https://dev.nominal.io/python/ref/generated/nominal.core.Asset.md#nominal.core.Asset.get_or_create_dataset "nominal.core.Asset.get_or_create_dataset") (see [Assets](https://dev.nominal.io/python/guides/assets.md#add-data-with-data-scopes)).
Then upload a file to it.

The examples upload `flight.csv`. To run them as written, save this sample under that name:

```text
time,altitude,temperature,tail_number
2026-09-10T14:38:19Z,100.0,20.0,N456QC
2026-09-10T14:38:20Z,101.5,20.2,N456QC
2026-09-10T14:38:21Z,103.0,20.4,N456QC
```

```python
dataset = client.create_dataset("Flight telemetry")
file = dataset.add_tabular_data("flight.csv", timestamp_column="time", timestamp_type="iso_8601")
file.poll_until_ingestion_completed()  # raises NominalIngestError if ingestion fails
print(dataset.nominal_url)
```

Each column other than `timestamp_column` becomes a channel.
`timestamp_type` describes the timestamp values, as in [Timestamp formats](https://dev.nominal.io/python/guides/datasets/csv.md#timestamp-formats).

Upload methods return a [`DatasetFile`](https://dev.nominal.io/python/ref/generated/nominal.core.DatasetFile.md#nominal.core.DatasetFile "nominal.core.DatasetFile") before ingestion finishes.
Wait for it before you read the new channels or the file’s bounds.

Uploading another file adds to the dataset rather than replacing its data.
Keep channel names, types and units the same across files.

## File formats

| Format | Method | Guide |
| --- | --- | --- |
| CSV, Parquet | [`add_tabular_data()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_tabular_data "nominal.core.Dataset.add_tabular_data") | [CSV](https://dev.nominal.io/python/guides/datasets/csv.md) |
| Journal JSON logs | [`add_journal_json()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_journal_json "nominal.core.Dataset.add_journal_json") | [Journal JSON](https://dev.nominal.io/python/guides/datasets/journal-json.md) |
| HDF5 | convert, then [`add_tabular_data()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_tabular_data "nominal.core.Dataset.add_tabular_data") | [HDF5](https://dev.nominal.io/python/guides/datasets/hdf-5.md) |
| PX4 ULog | convert, then [`add_tabular_data()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_tabular_data "nominal.core.Dataset.add_tabular_data") | [PX4](https://dev.nominal.io/python/guides/datasets/px-4.md) |
| Avro streams | [`add_avro_stream()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_avro_stream "nominal.core.Dataset.add_avro_stream") | [Avro streams](https://dev.nominal.io/python/guides/datasets/avro-streams.md) |
| MCAP | [`add_mcap()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_mcap "nominal.core.Dataset.add_mcap") | [MCAP video ingest](https://dev.nominal.io/python/guides/video/mcap-video-ingest.md) |
| Video | [`add_video()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_video "nominal.core.Dataset.add_video") | [Video ingest](https://dev.nominal.io/python/guides/video/video-ingest.md) |
| Other binary formats | [`add_containerized()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.add_containerized "nominal.core.Dataset.add_containerized") | [File extractors](https://dev.nominal.io/python/guides/extractors/overview.md) |

To send values as they’re produced, [stream](https://dev.nominal.io/python/guides/streaming/overview.md) them instead.

## Inspect channels and files

```python
dataset.refresh()
print(dataset.bounds)  # start and end in epoch nanoseconds, or None

for channel in dataset.get_channels():
    print(channel.name, channel.data_type, channel.unit)

for f in dataset.list_files(successful_only=False):  # include failed and pending files
    print(f.name, f.ingest_status.name)
```

The dataset’s bounds span all its files. `file.bounds` covers one file.

To set channel types and units, see [Channels and data types](https://dev.nominal.io/python/guides/datasets/channels.md).

## Retrieve a dataset

Retrieve a dataset by the RID on its page in Nominal, or search by name and labels with [`search_datasets()`](https://dev.nominal.io/python/ref/generated/nominal.core.NominalClient.md#nominal.core.NominalClient.search_datasets "nominal.core.NominalClient.search_datasets"):

```python
dataset = client.get_dataset("<DATASET_RID>")
```

This returns the dataset’s metadata, not its data. To download data, see [Export data](https://dev.nominal.io/python/guides/datasets/export-data.md).

## Update metadata

[`update()`](https://dev.nominal.io/python/ref/generated/nominal.core.Dataset.md#nominal.core.Dataset.update "nominal.core.Dataset.update") replaces each field you pass and leaves the others unchanged.
To add a property, merge it with the existing ones:

```python
dataset.update(labels=["flight-test"], properties={**dataset.properties, "campaign": "2026-09"})
```

Labels and properties describe the whole dataset.
To select part of its data, use [tags](https://dev.nominal.io/python/guides/streaming/overview.md#add-tags-to-filter-data-in-a-run-or-asset).
