# Ranges

> Organizing telemetry data with time-based ranges and metadata.

![](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/preview-light.png)

[Ranges](https://docs.synnaxlabs.com/reference/concepts/ranges) are named time intervals that organize telemetry into tests, runs, and events, and carry metadata about them.

## Range parameters

| Parameter                 | Type                                                                             | Required | Default | Description                                                                                                     |
| ------------------------- | -------------------------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------- |
| `name`                    | string                                                                           | Yes      | -       | Human-readable name for the range                                                                               |
| `time_range`              | [`TimeRange`](https://docs.synnaxlabs.com/reference/client/time-types#timerange) | Yes      | -       | Time interval spanned by the range (start must be ≤ end)                                                        |
| `color`                   | string                                                                           | No       | `""`    | Hex color code for identifying the range in visualizations (e.g., `"#FF0000"`)                                  |
| `key`                     | `UUID`                                                                           | No       | Auto    | Unique identifier (automatically generated by Synnax if not provided)                                           |
| `parent`                  | `Range`                                                                          | No       | `None`  | Optional parent range. Pass the parent `Range` itself.                                                          |
| `retrieve_if_name_exists` | boolean                                                                          | No       | `False` | If `True`, retrieves existing range with same name and time range instead of creating a duplicate. Python only. |

> TypeScript does not support conditional range creation.

## Create a range

**Console**

Create a range via the toolbar, [command palette](https://docs.synnaxlabs.com/reference/console/ui-overview#search-and-command-palette), or a plot region.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/create-dark.mp4#t=0.001)

**Python**

To create a range, use the `client.ranges.create` method:

```python
import synnax as sy

# Create a range with a specific time interval
start = sy.TimeStamp("2023-02-12 12:30:00")
end = sy.TimeStamp("2023-02-12 14:30:00")

my_range = client.ranges.create(
    name="My Range",
    time_range=sy.TimeRange(start=start, end=end),
    retrieve_if_name_exists=True,  # Return the existing range instead of a duplicate
)

# Or use the convenience span_range method
start = sy.TimeStamp.now()
my_range = client.ranges.create(
    name="My Range",
    time_range=start.span_range(sy.TimeSpan.HOUR * 2),
)
```

**TypeScript**

To create a range, use the `client.ranges.create` method:

```typescript
import { TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/client";

// Create a range with a specific time interval
const start = new TimeStamp("2023-02-12 12:30:00");
const end = new TimeStamp("2023-02-12 14:30:00");

const range = await client.ranges.create({
  name: "My Range",
  timeRange: new TimeRange(start, end),
  // No retrieveIfNameExists option in TypeScript
});

// Or use the convenience span method
const start = TimeStamp.now();
const range = await client.ranges.create({
  name: "My Range",
  timeRange: start.span(TimeSpan.hours(2)),
});
```

### Create child ranges

[Child ranges](https://docs.synnaxlabs.com/reference/concepts/ranges#child-ranges) segment a range into smaller intervals.

**Console**

Set the parent range field in the creation dialog, or click `Add Child Range` in the range overview page.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/create-child-dark.mp4#t=0.001)

**Python**

The most convenient way is the `create_child_range` shorthand on a parent `Range`:

```python
child_range = parent_range.create_child_range(
    name="My Child Range",
    time_range=sy.TimeRange(start=start, end=end),
)
```

You can also pass the parent `Range` directly to `client.ranges.create` via the `parent` keyword. This form works for one or many children:

```python
child_range = client.ranges.create(
    name="My Child Range",
    time_range=sy.TimeRange(start=start, end=end),
    parent=parent_range,
)
```

Or set `parent` on the `Range` itself when constructing it — useful when batching:

```python
client.ranges.create([
    sy.Range(name="Child A", time_range=tr_a, parent=parent_range),
    sy.Range(name="Child B", time_range=tr_b, parent=parent_range),
])
```

**TypeScript**

Pass the parent `Range` directly on the child being created. This form works for one or many children:

```typescript
const childRange = await client.ranges.create({
  name: "My Child Range",
  timeRange: new TimeRange(start, end),
  parent: parentRange,
});
```

Or set `parent` on each range when batching:

```typescript
await client.ranges.create([
  { name: "Child A", timeRange: trA, parent: parentRange },
  { name: "Child B", timeRange: trB, parent: parentRange },
]);
```

## Retrieve ranges

### Single

Retrieve a range by its name or key. Synnax will raise a `NotFoundError` if the range does not exist, and a `MultipleFoundError` if multiple ranges with the given name exist.

**Python**

```python
# By name
my_range = client.ranges.retrieve(name="My Range")

# By key
my_range = client.ranges.retrieve(key=my_range.key)
```

**TypeScript**

```typescript
// By name
const myRange = await client.ranges.retrieve("My Range");

// By key
const myRange = await client.ranges.retrieve(myRange.key);
```

### Multiple

Retrieve multiple ranges by passing a list of names or keys. When retrieving multiple ranges, Synnax will not raise an error if a range cannot be found. Instead, the missing range will be omitted from the returned list.

**Python**

```python
# By name
my_ranges = client.ranges.retrieve(names=["My Range", "My Other Range"])

# By key
my_ranges = client.ranges.retrieve(keys=[my_range.key, my_other_range.key])

# By search term
ranges = client.ranges.search("Hotfire")
```

**TypeScript**

```typescript
// By name
const myRanges = await client.ranges.retrieve(["My Range", "My Other Range"]);

// By key
const myRanges = await client.ranges.retrieve([myRange.key, myOtherRange.key]);

// By search term
const ranges = await client.ranges.retrieve({ searchTerm: "Hotfire" });
```

### Child

If a range has child ranges, you can retrieve them directly from the parent range.

**Python**

```python
child_ranges = my_range.children
```

**TypeScript**

```typescript
const childRanges = await myRange.retrieveChildren();
```

### Parent

Navigate up the hierarchy by retrieving a child range’s parent.

**Python**

> Retrieving a parent range is not directly supported in Python.

**TypeScript**

```typescript
const parentRange = await myRange.retrieveParent();
```

## Update a range

To update an existing range, use the same `client.ranges.create` method but specify the `key` of the range to update. This allows modification of the range’s name, time range, or color.

**Python**

```python
import synnax as sy

# First, retrieve the range you want to update
my_range = client.ranges.retrieve(name="My Range")

# Update the range by providing its key and new values
updated_range = client.ranges.create(
    key=my_range.key,  # Specify the key to update existing range
    name="My Updated Range",  # New name
    time_range=sy.TimeRange(
        start=sy.TimeStamp("2023-02-12 13:00:00"),
        end=sy.TimeStamp("2023-02-12 15:00:00"),
    ),
    color="#00FF00",  # New color
)
```

**TypeScript**

```typescript
import { TimeRange, TimeStamp } from "@synnaxlabs/client";

// First, retrieve the range you want to update
const myRange = await client.ranges.retrieve("My Range");

// Update the range by providing its key and new values
const updatedRange = await client.ranges.create({
  key: myRange.key, // Specify the key to update existing range
  name: "My Updated Range", // New name
  timeRange: new TimeRange(
    new TimeStamp("2023-02-12 13:00:00"),
    new TimeStamp("2023-02-12 15:00:00"),
  ),
  color: "#00FF00", // New color
});
```

When updating a range, you must provide the `key` parameter. If you provide a `key` that doesn’t exist, Synnax will create a new range with that key instead of raising an error.

> Updating a range will completely replace its properties. Make sure to include all the properties you want to keep, not just the ones you want to change.

## Metadata

Ranges can store metadata as key-value pairs. This is useful for attaching information like test configuration parameters, numeric results, or part numbers.

All metadata values are stored as strings. It’s up to you to correctly cast the values to the appropriate type.

### Set

**Console**

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/set-metadata-dark.mp4#t=0.001)

**Python**

```python
my_range = client.ranges.retrieve(name="My Range")

# Set a single key/value pair
my_range.meta_data.set("part_number", "12345")

# Another way to set a single key/value pair
my_range.meta_data["part_number"] = "12345"

# Set multiple key/value pairs
my_range.meta_data.set({
    "part_number": "12345",
    "test_configuration": "Test 1",
    "test_result": "123.45",
})
```

**TypeScript**

```typescript
const myRange = await client.ranges.retrieve("My Range");

// Set a single key/value pair
await myRange.kv.set("part_number", "12345");

// TypeScript only supports the set() method
// (no bracket syntax)

// Set multiple key/value pairs
await myRange.kv.set({
  part_number: "12345",
  test_configuration: "Test 1",
  test_result: "123.45",
});
```

### Get

**Python**

```python
my_range = client.ranges.retrieve(name="My Range")

# Retrieve a single key
part_number = my_range.meta_data["part_number"] # Or use .get("key")

# Retrieve multiple keys
metadata = my_range.meta_data.get(["part_number", "test_configuration"])

# List all metadata
all_metadata = my_range.meta_data.get([])
```

**TypeScript**

```typescript
const myRange = await client.ranges.retrieve("My Range");

// Retrieve a single key
const partNumber = await myRange.kv.get("part_number");

// Retrieve multiple keys
const metadata = await myRange.kv.get(["part_number", "test_configuration"]);

// List all metadata
const allMetadata = await myRange.kv.list();
```

### Delete

**Python**

```python
my_range = client.ranges.retrieve(name="My Range")

# Delete a single key
del my_range.meta_data["part_number"] # Or use .delete("key")

# Delete multiple keys
my_range.meta_data.delete(["part_number", "test_configuration"])
```

**TypeScript**

```typescript
const myRange = await client.ranges.retrieve("My Range");

// Delete a single key
await myRange.kv.delete("part_number");

// Delete multiple keys
await myRange.kv.delete(["part_number", "test_configuration"]);
```

## Labels

Labels categorize and filter ranges.

**Console**

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/labels-dark.mp4#t=0.001)

**Python**

```python
my_range = client.ranges.retrieve(name="My Range")

# List the labels on the range
for label in my_range.labels:
    print(label.name)
```

> Labels are read-only in the Python client.

**TypeScript**

```typescript
const myRange = await client.ranges.retrieve("My Range");

// Create a label
const label = await client.labels.create({ name: "Hotfire", color: "#FF0000" });

// Add the label to the range
await myRange.addLabel(label.key);

// List the labels on the range
const labels = await myRange.retrieveLabels();

// Remove the label from the range
await myRange.removeLabel(label.key);
```

## Read from a range

Ranges provide a convenient way to read data without specifying exact time boundaries. Once you have a range, you can read channel data directly from it.

**Python**

```python
my_range = client.ranges.retrieve("My Interesting Test")

# Read data from a single channel
data = my_range.my_precise_tc.read()

# Read data from multiple channels
frame = my_range.read(["my_precise_tc", "my_precise_pt"])

# Python allows direct use of channel names as properties
celsius = my_range.my_precise_tc - 273.15
```

**TypeScript**

```typescript
const myRange = await client.ranges.retrieve("My Interesting Test");

// Read data from a single channel
const data = await myRange.read("my_precise_tc");

// Read data from multiple channels
const frame = await myRange.read(["my_precise_tc", "my_precise_pt"]);

// Convert from Kelvin to Celsius
const celsius = data.map((v) => v - 273.15);
```

### Read by alias

Once you’ve set an [alias](https://docs.synnaxlabs.com/reference/client/channels#channel-aliases), you can access the channel using that alias.

**Python**

Python allows you to access aliased channels directly as properties:

```python
burst_test = client.ranges.retrieve(name="Oct 10 Burst Test")

# Access by alias as a property
data = burst_test.tank_pressure

# Or use dictionary syntax
data = burst_test["tank_pressure"]

# Regex returns a list of matching channels
tank_channels = burst_test["^tank"]
```

**TypeScript**

TypeScript requires resolving the alias to a channel key first:

```typescript
const burstTest = await client.ranges.retrieve("Oct 10 Burst Test");

// Resolve alias to channel key, then read
const channelKey = await burstTest.resolveAlias("tank_pressure");

// Then read by channel key
const data = await burstTest.read(channelKey);

// Or read directly by original channel name
const data2 = await burstTest.read("daq_analog_input_1");
```

## Write to a range

Writing to a range removes the burden of needing to correctly align the timestamps for different channels. The write will assume that the timestamp of the first sample is the start of the range.

**Python**

```python
my_range = client.ranges.retrieve("My Interesting Test")

temperatures = [55, 55.1, 55.7, 57.2, 58.1, 58.9, 59.1, 59.2, 59.3]
pressures = [100, 100.1, 100.7, 102.2, 103.1, 103.9, 104.1, 104.2, 104.3]

my_range.write({
    "my_precise_tc": temperatures,
    "my_precise_pt": pressures,
})
```

**TypeScript**

> Writing to ranges is not supported in TypeScript.

## Delete a range

**Console**

![](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/client/ranges/delete-light.png)

**Python**

Delete a range by passing its key to the `client.ranges.delete` method.

```python
# Delete a single range
client.ranges.delete(my_range.key)

# Delete multiple ranges
client.ranges.delete([my_range.key, my_other_range.key])
```

**TypeScript**

Delete a range by passing its key to the `client.ranges.delete` method.

```typescript
// Delete a single range
await client.ranges.delete(myRange.key);

// Delete multiple ranges
await client.ranges.delete([myRange.key, myOtherRange.key]);
```
