Skip to content

Dataset

Inherits: RefCounted
Namespace: TauPlot

Holds all X and Y sample data for one or more named series and notifies the plot of every change.

Description

Dataset is the data model of TauPlot. It carries all sample values passed to a plot via TauPlot.plot_xy(). Every mutation emits the changed signal with a DatasetChange describing what moved, which the plot uses internally to trigger the minimum required update. Callers never need to refresh the plot manually after modifying a dataset.

A dataset holds one or more series. Each series has a name, a stable integer ID assigned at creation, and a pair of X and Y ring buffers. The series name appears in the legend. The series ID is referenced by TauXYSeriesBinding to map a series to a pane, an overlay type, and a Y axis.

A dataset operates in one of two Mode values, fixed at construction.

SHARED_X all series share a single ordered X buffer. Every append adds one X value and one Y value per series simultaneously. Use this mode when all series are sampled at the same positions: a bar chart where every group has the same labels, or a time series where every series records a value at every timestamp.

PER_SERIES_X each series owns independent X and Y buffers and can have a different sample count and different X positions. Use this mode for scatter plots where each group of points has its own coordinates.

X values are either NUMERIC (float, 64-bit) or CATEGORY (String), also fixed at construction.

All buffers are ring buffers with a fixed capacity. When a buffer is full, appending a new sample drops the oldest one. This makes Dataset suitable for real-time streaming where only the most recent N samples are displayed.

Example

# Two sensors sampled at the same timestamps, keeping the last 256 samples.
var dataset := TauPlot.Dataset.new(
    TauPlot.Dataset.Mode.SHARED_X,
    TauPlot.Dataset.XElementType.NUMERIC,
    256
)
var id_a := dataset.add_series("Sensor A")
var id_b := dataset.add_series("Sensor B")

# ---

# One append per measurement round, one Y value per registered series.
# Once 256 samples are stored, every append drops the oldest one.
dataset.append_shared_sample(Time.get_ticks_msec() / 1000.0, PackedFloat64Array([17.0, 42.0]))

Notes

  1. Mode and element type are immutable. To use a different combination, create a new Dataset and call plot_xy() again.

  2. Series IDs are stable. An ID returned by add_series() stays valid across reordering and renaming.

  3. Series order controls rendering order. The visual order of series in bars, the legend, and stacking is determined by series position in the internal array. reorder_series() changes that position.

  4. SHARED_X add-series constraint. add_series() can only be called before any samples exist. Once samples are present, use add_series_with_initial_y() to align the new Y buffer with the existing shared X buffer.

  5. Logical sample indices convention. All methods that accept a p_logical_sample_index parameter use the same convention: index 0 is the oldest sample currently in the buffer, and get_shared_sample_count() - 1 (or get_series_sample_count() - 1 in PER_SERIES_X mode) is the most recently appended one. Indices are stable as long as no new sample is appended. When the ring buffer is full and a new sample is appended, every logical index shifts by one: the sample that was at index 1 is now at index 0, and the new sample occupies the last position. Accessing an out-of-range index logs an error.

Enums

Mode

Controls how X buffers are organized across series.

Value Meaning
SHARED_X All series share one X buffer. Sample index i maps to the same X value for every series.
PER_SERIES_X Each series owns independent X and Y buffers with its own sample count and X positions.

XElementType

Controls the type stored in X buffers.

Value Meaning
NUMERIC X values are float (64-bit). Use for continuous numeric axes.
CATEGORY X values are String. Use for categorical axes such as bar chart group labels.

Signals

changed()

changed(p_change: DatasetChange)

Emitted after every mutation, or once per begin_batch() / end_batch() block. The plot connects to this signal internally and uses it to decide whether to redraw or recompute the domain. Not emitted if a batch closes with no actual data change.

p_change is a DatasetChange. Its type says how the dataset changed and selects which of the remaining fields carry a meaningful value.

Constructor

new()

Dataset.new(
    p_mode: Mode, 
    p_x_element_type: XElementType,
    p_shared_capacity: int = 1024
) -> Dataset

Creates an empty dataset with no series and no samples.

Parameters


make_shared_x_categorical()

make_shared_x_categorical(
    p_series_names: PackedStringArray,
    p_x: PackedStringArray,
    p_y_by_series: Array[PackedFloat64Array],
    p_capacity: int = -1
) -> Dataset

Convenience constructor that creates a SHARED_X / CATEGORY dataset from bulk arrays. Returns null on error.

Parameters

  • p_series_names: PackedStringArray One name per series. Must not be empty.
  • p_x: PackedStringArray Category labels for the shared X axis.
  • p_y_by_series: Array[PackedFloat64Array] One PackedFloat64Array per series. Each inner array must have exactly p_x.size() values.
  • p_capacity: int Ring buffer capacity. Pass -1 (default) to set it equal to p_x.size(), which is the right choice for static datasets. Pass a larger value to leave room for future appends.

Array size constraints

  • p_y_by_series.size() must equal p_series_names.size().
  • Every p_y_by_series[i].size() must equal p_x.size().

make_shared_x_continuous()

make_shared_x_continuous(
    p_series_names: PackedStringArray,
    p_x: PackedFloat64Array,
    p_y_by_series: Array[PackedFloat64Array],
    p_capacity: int = -1
) -> Dataset

Convenience constructor that creates a SHARED_X / NUMERIC dataset from bulk arrays. Returns null on error.

Parameters

  • p_series_names: PackedStringArray One name per series. Must not be empty.
  • p_x: PackedFloat64Array Numeric X values for the shared axis.
  • p_y_by_series: Array[PackedFloat64Array] One PackedFloat64Array per series. Each inner array must have exactly p_x.size() values.
  • p_capacity: int Ring buffer capacity. Pass -1 (default) to set it equal to p_x.size(), which is the right choice for static datasets. Pass a larger value to leave room for future appends.

Array size constraints

  • p_y_by_series.size() must equal p_series_names.size().
  • Every p_y_by_series[i].size() must equal p_x.size().

make_per_series_x_continuous()

make_per_series_x_continuous(
    p_series_names: PackedStringArray,
    p_x_by_series: Array[PackedFloat64Array],
    p_y_by_series: Array[PackedFloat64Array],
    p_capacity_by_series: PackedInt32Array = PackedInt32Array()
) -> Dataset

Convenience constructor that creates a PER_SERIES_X / NUMERIC dataset from bulk arrays. Each series has its own X and Y arrays and may have a different sample count. Returns null on error.

Parameters

  • p_series_names: PackedStringArray One name per series. Must not be empty.
  • p_x_by_series: Array[PackedFloat64Array] One X array per series.
  • p_y_by_series: Array[PackedFloat64Array] One Y array per series. Each inner array must have the same size as the corresponding X array.
  • p_capacity_by_series: PackedInt32Array Optional per-series ring buffer capacities. Pass an empty array (default) to set each series capacity equal to its initial sample count. When provided, must have exactly p_series_names.size() entries, and each value is clamped to a minimum of 1.

Array size constraints

  • p_x_by_series.size() must equal p_series_names.size().
  • p_y_by_series.size() must equal p_series_names.size().
  • For every series i, p_y_by_series[i].size() must equal p_x_by_series[i].size().
  • If p_capacity_by_series is non-empty, its size must equal p_series_names.size().

Methods

Introspection

get_mode()

get_mode() -> Mode

Returns the Mode set at construction.


get_x_element_type()

get_x_element_type() -> XElementType

Returns the XElementType set at construction.


is_batching()

is_batching() -> bool

Returns true if at least one batch is currently open.


Series lifetime

add_series()

add_series(p_series_name: String, p_capacity: int = 1024) -> int

Registers a new empty series to the dataset and returns a stable ID valid across reordering and renaming.

Parameters

  • p_series_name: String Display name shown in the legend.
  • p_capacity: int Ring buffer capacity. Only used in PER_SERIES_X mode. Values below 1 are clamped to 1. Default: 1024.

Notes


add_series_with_initial_y()

add_series_with_initial_y(p_series_name: String, p_capacity: int, p_initial_y_values: PackedFloat64Array) -> int

Registers a new series in SHARED_X mode when samples already exist. The initial Y array fills the new series buffer so it aligns with the existing shared X buffer.

Parameters

  • p_series_name: String Display name shown in the legend.
  • p_capacity: int Ring buffer capacity. Values below 1 are clamped to 1.
  • p_initial_y_values: PackedFloat64Array Must have exactly get_shared_sample_count() values. Pass an empty array if the dataset has no samples yet (equivalent to add_series() in that case).

Returns -1 and logs an error on failure.


remove_series()

remove_series(p_series_id: int) -> void

Removes the series and its buffers. Emits changed. Logs an error if the ID is unknown.


has_series()

has_series(p_series_id: int) -> bool

Returns true if a series with the given ID exists.


get_series_count()

get_series_count() -> int

Returns the number of series currently registered.


get_series_ids()

get_series_ids() -> PackedInt64Array

Returns a copy of the series ID array in current visual order.


get_series_names()

get_series_names() -> PackedStringArray

Returns a copy of the series name array in current visual order. Index i corresponds to index i in get_series_ids().


get_series_name()

get_series_name(p_series_id: int) -> String

Returns the name of the series with the given ID. Returns an empty string if the ID is unknown.


set_series_name()

set_series_name(p_series_id: int, p_name: String) -> void

Renames the series. The updated name appears in the legend on the next plot refresh. Emits changed. Logs an error if the ID is unknown.


get_series_index_by_id()

get_series_index_by_id(p_series_id: int) -> int

Returns the zero-based position of the series in the current visual order. Returns -1 if the ID is unknown.


get_series_id_by_index()

get_series_id_by_index(p_series_index: int) -> int

Returns the series ID at the given visual position. Returns -1 if the index is out of range.


Series order

reorder_series()

reorder_series(p_new_order_series_ids: PackedInt64Array) -> void

Reorders series to match the given ID sequence. The array must contain every existing series ID exactly once. Affects the legend order and bar rendering order. Emits changed.


Capacity

get_shared_capacity()

get_shared_capacity() -> int

Returns the shared ring buffer capacity. Only valid in SHARED_X mode. Logs an error and returns 0 in PER_SERIES_X mode.


set_shared_capacity()

set_shared_capacity(p_capacity: int) -> void

Resizes all X and Y buffers to the new shared capacity. Values below 1 are clamped to 1. If the new capacity is smaller than the current sample count, the oldest samples are dropped. Only valid in SHARED_X mode. Emits changed.


get_series_capacity()

get_series_capacity(p_series_id: int) -> int

Returns the ring buffer capacity for the given series. In SHARED_X mode, returns the shared capacity. In PER_SERIES_X mode, returns the per-series capacity.


set_series_capacity()

set_series_capacity(p_series_id: int, p_capacity: int) -> void

Resizes the X and Y buffers of the given series. Values below 1 are clamped to 1. If the new capacity is smaller than the current sample count, the oldest samples are dropped. Only valid in PER_SERIES_X mode. Emits changed.


Sample counts

get_shared_sample_count()

get_shared_sample_count() -> int

Returns the number of samples currently stored in the shared X buffer. Only valid in SHARED_X mode. Logs an error and returns 0 in PER_SERIES_X mode.


get_series_sample_count()

get_series_sample_count(p_series_id: int) -> int

Returns the number of samples for the given series. In SHARED_X mode all series have the same count. In PER_SERIES_X mode each series may differ.


Appending samples

append_shared_sample()

append_shared_sample(p_x: Variant, p_y_values: PackedFloat64Array) -> void

Appends one sample to the shared X buffer and one Y value to every series Y buffer. This is the primary write method for SHARED_X streaming datasets. If the buffer is full, the oldest sample is dropped. Only valid in SHARED_X mode.

p_x must be a String when XElementType is CATEGORY, and a float when it is NUMERIC. p_y_values must contain exactly one value per registered series.


append_sample_to_one_series()

append_sample_to_one_series(p_series_id: int, p_x: Variant, p_y: float) -> void

Appends one X/Y sample to the buffers of the specified series. This is the primary write method for PER_SERIES_X streaming datasets. If the buffer is full, the oldest sample is dropped. Only valid in PER_SERIES_X mode.

p_x must be a float (only NUMERIC is supported in PER_SERIES_X mode).


Reading and writing values

get_shared_x()

get_shared_x(p_logical_sample_index: int) -> Variant

Returns the X value at the given index from the shared X buffer. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Returns null in PER_SERIES_X mode. The return type is String for CATEGORY, float for NUMERIC.


get_shared_x_numeric_slice()

get_shared_x_numeric_slice(p_start_index: int, p_count: int) -> PackedFloat64Array

Returns p_count shared X values, starting at logical sample index p_start_index. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. The returned array is a copy, so writing to it does not change the dataset.

Needs SHARED_X mode and a NUMERIC X element type. A CATEGORY dataset stores strings, so it has no float row to return. In any other case, or when the range goes outside the stored samples, the method logs an error and returns an empty array.

Reading a whole range at once is faster than calling get_shared_x() for each sample, and the result is typed instead of Variant.

Parameters

  • p_start_index: int Logical sample index of the first value to read.
  • p_count: int How many values to read. p_start_index + p_count must not be greater than get_shared_sample_count().

set_shared_x()

set_shared_x(p_logical_sample_index: int, p_x: Variant) -> void

Overwrites the X value at the given index in the shared X buffer. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Only valid in SHARED_X mode. Emits changed for all series.


get_series_x()

get_series_x(p_series_id: int, p_logical_sample_index: int) -> Variant

Returns the X value at the given index for the specified series. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Returns null in SHARED_X mode or if the ID is unknown. The return type matches the XElementType set at construction.


get_series_x_numeric_slice()

get_series_x_numeric_slice(p_series_id: int, p_start_index: int, p_count: int) -> PackedFloat64Array

Returns p_count X values of one series, starting at logical sample index p_start_index. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. The returned array is a copy, so writing to it does not change the dataset.

Needs PER_SERIES_X mode and a NUMERIC X element type. A CATEGORY dataset stores strings, so it has no float row to return. In any other case, when the ID is unknown, or when the range goes outside the stored samples, the method logs an error and returns an empty array.

Reading a whole range at once is faster than calling get_series_x() for each sample, and the result is typed instead of Variant.

Parameters

  • p_series_id: int ID of the series to read.
  • p_start_index: int Logical sample index of the first value to read.
  • p_count: int How many values to read. p_start_index + p_count must not be greater than get_series_sample_count().

set_series_x()

set_series_x(p_series_id: int, p_logical_sample_index: int, p_x: Variant) -> void

Overwrites the X value at the given index for the specified series. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Only valid in PER_SERIES_X mode. Emits changed for the affected series.


get_series_y()

get_series_y(p_series_id: int, p_logical_sample_index: int) -> float

Returns the Y value at the given index for the specified series. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Logs an error and returns 0.0 if the ID is unknown.

Reading an empty series, or a logical index below 0 or at or above get_series_sample_count(), pushes an error and returns 0.0. A returned 0.0 is therefore not proof that a sample holds that value.


get_series_y_slice()

get_series_y_slice(p_series_id: int, p_start_index: int, p_count: int) -> PackedFloat64Array

Returns p_count Y values of one series, starting at logical sample index p_start_index. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. The returned array is a copy, so writing to it does not change the dataset.

Logs an error and returns an empty array when the ID is unknown, or when the range goes outside the stored samples. If p_count is 0 or less, the method returns an empty array and logs nothing.

Reading a whole range at once is faster than calling get_series_y() for each sample. It is the read counterpart of set_series_y_slice().

Parameters

  • p_series_id: int ID of the series to read.
  • p_start_index: int Logical sample index of the first value to read.
  • p_count: int How many values to read. p_start_index + p_count must not be greater than get_series_sample_count().

set_series_y()

set_series_y(p_series_id: int, p_logical_sample_index: int, p_y: float) -> void

Overwrites the Y value at the given index for the specified series. Index 0 is the oldest sample in the buffer, count - 1 is the most recent. Emits changed for the affected series.


set_series_y_slice()

set_series_y_slice(p_series_id: int, p_start_index: int, p_values: PackedFloat64Array) -> void

Overwrites a contiguous range of Y values starting at p_start_index. Writes as many values as fit within the buffer from that index forward. Emits changed for the affected series, and emits nothing when no value is written.


Batch updates

begin_batch()

begin_batch() -> void

Opens a batch. All mutations accumulate into a single changed emission instead of firing once per mutation. Batches nest: each call must be matched by end_batch().


end_batch()

end_batch() -> void

Closes the current batch level. At the outermost level, emits changed once with the aggregated change. If no data changed, the signal is not emitted.

Calling this without a matching begin_batch() logs an error.


Clearing data

clear_samples()

clear_samples() -> void

Removes all samples from all buffers. Series registrations are preserved. Emits changed.


reset()

reset() -> void

Removes all series and all samples. The shared X buffer is recreated in SHARED_X mode. Emits changed with the series IDs that existed before the reset.

  • TauPlot The plot node. Calls plot_xy() to attach a dataset and connects to changed internally.
  • DatasetChange Payload of the changed signal, describing one change.
  • TauXYSeriesBinding Maps a series ID to a pane, overlay type, and Y axis. Passed to plot_xy() alongside the dataset.