Example usage: RESTful API

In this example, we will show you how to use the dunderlab.api library to interact with the RESTful API provided by the TimescaleDB App.

[3]:
from dunderlab.api import aioAPI as API
from dunderlab.api.utils import JSON

api = API('http://127.0.0.1:51102/timescaledbapp/', token=TOKEN)
  1. First, import the aioAPI class from the dunderlab.api module, and give it an alias API.

  2. Next, create an instance of the API class by providing the base URL of the TimescaleDB App RESTful API (in this case, it’s http://localhost:8000/realtimedbapp/).

Now, you have an api object that can be used to interact with the TimescaleDB App’s RESTful API.

Fetching available API endpoints

In this section, you will learn how to obtain the available API endpoints for the TimescaleDB App. This information will help you understand the different endpoints and their functionalities, enabling you to make the most of the TimescaleDB App API in your projects.

[4]:
endopoints = await api.endpoints()
JSON(endopoints)

{
  "source": "http://127.0.0.1:51102/timescaledbapp/source/",
  "measure": "http://127.0.0.1:51102/timescaledbapp/measure/",
  "channel": "http://127.0.0.1:51102/timescaledbapp/channel/",
  "chunk": "http://127.0.0.1:51102/timescaledbapp/chunk/",
  "timeserie": "http://127.0.0.1:51102/timescaledbapp/timeserie/",
}
  1. Call the endpoints() method on the api object using the await keyword.

  2. This method returns a list of available API endpoints for the TimescaleDB App.

Make sure to use this snippet within an asynchronous context, such as inside an async def function or a Jupyter notebook cell with !pip install nest_asyncio and import nest_asyncio; nest_asyncio.apply() executed beforehand.

Create timeseries environment

Adding a new data source

In this section, you will learn how to add a new data source using the TimescaleDB App API. By following the provided instructions, you can easily integrate new data sources into your projects and enhance their functionality.

[5]:
source_response = await api.source.post({
    'label': 'Test.v1',
    'name': 'Test Database',
    'location': 'Eje Cafetero',
    'device': 'None',
    'protocol': 'None',
    'version': '0.1',
    'description': 'Sample database for TimeScaleDBApp',
})

JSON(source_response)

{
  "label": "Test.v1",
  "name": "Test Database",
  "location": "Eje Cafetero",
  "device": "None",
  "protocol": "None",
  "version": "0.1",
  "description": "Sample database for TimeScaleDBApp",
  "created": "2023-10-08T21:38:43.512360Z",
}
  1. Call the post() method on the api.source object using the await keyword.

  2. Provide a dictionary containing the required information for the new data source:

    • 'label': A string representing the data source name.

    • 'name': A string representing the name of the data source.

    • 'location': A string representing the location of the data source.

    • 'device': A string representing the device used for the data source.

    • 'protocol': A string representing the communication protocol used by the data source.

    • 'version': A string representing the version of the data source.

    • 'description':

Make sure to use this snippet within an asynchronous context, such as inside an async def function or a Jupyter notebook cell with !pip install nest_asyncio and import nest_asyncio; nest_asyncio.apply() executed beforehand.

Retrieving data sources

In this section, you will learn how to retrieve the data sources using the TimescaleDB App API. This will allow you to access and manage the data sources associated with your projects, ensuring efficient data handling and organization.

[6]:
source_retrieve = await api.source.get()
JSON(source_retrieve)

{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "label": "Test.v1",
      "name": "Test Database",
      "location": "Eje Cafetero",
      "device": "None",
      "protocol": "None",
      "version": "0.1",
      "description": "Sample database for TimeScaleDBApp",
      "created": "2023-10-08T21:38:43.512360Z",
    }],
}
<frozen abc>:123: RuntimeWarning: coroutine 'aioAPI.endpoints' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
  1. Call the get() method on the api.source object using the await keyword.

  2. The method returns a dictionary containing the list of data sources and their details.

Adding a new measurement

In this section, you will learn how to add a new measurement using the TimescaleDB App API. This will enable you to expand the scope of your data analysis and easily incorporate new metrics into your projects.

[7]:
measure_response = await api.measure.post({
    'source': 'Test.v1',
    'label': 'measure_01',
    'name': 'Measure 01',
    'description': 'Simple sinusoidals for 64 channels at different frequencies',
})

JSON(measure_response)

{
  "label": "measure_01",
  "name": "Measure 01",
  "description": "Simple sinusoidals for 64 channels at different frequencies",
  "source": "Test.v1",
}
  1. Call the post() method on the api.measure object using the await keyword.

  2. Provide a dictionary containing the required information for the new measurement:

    • 'source': A string representing the data source name, which should match the source added earlier.

    • 'label': A string representing the short label for the measurement.

    • 'name': A string representing the full name or description of the measurement.

    • 'description':

Retrieving measurements

In this section, you will learn how to retrieve the measurements using the TimescaleDB App API. This will help you access and manage the metrics associated with your projects, ensuring proper data analysis and visualization.

[8]:
measure_retrieve = await api.measure.get({"source": "Test.v1"})
JSON(measure_retrieve)

{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "label": "measure_01",
      "name": "Measure 01",
      "description": "Simple sinusoidals for 64 channels at different frequencies",
      "source": "Test.v1",
    }],
}
  1. Call the get() method on the api.measure object using the await keyword.

  2. The method returns a dictionary containing the list of measurements and their details.

Adding multiple channels

In this section, you will learn how to add multiple channels using the TimescaleDB App API. This will allow you to efficiently manage and organize multiple data streams, improving the overall performance and functionality of your projects.

[9]:
channels_names = ['Fp1','Fp2','F7','F3','Fz','F4','F8','T7','T8','P7','P3','Pz','P4','P8','O1','O2']

channel_response = await api.channel.post([{
    'source': 'Test.v1',
    'measure': 'measure_01',
    'name': f'Channel {channel}',
    'label': f'{channel}',
    'unit': 'u',
    'sampling_rate': '1000',
} for channel in channels_names])

JSON(channel_response)
[
  {
    "label": "Fp1",
    "name": "Channel Fp1",
    "unit": "u",
    "sampling_rate": 1000.0,
    "description": null,
    "measure": "measure_01",
    "source": "Test.v1",
  },
  {
    "label": "Fp2",
    "name": "Channel Fp2",
    "unit": "u",
    "sampling_rate": 1000.0,
    "description": null,
    "measure": "measure_01",
    "source": "Test.v1",
  },
  {
    "label": "F7",
    "name": "Channel F7",
    "unit": "u",
    "sampling_rate": 1000.0,
    "description": null,
    "measure": "measure_01",
    "source": "Test.v1",
  },
  {
    "label": "F3",
    "name": "Channel F3",
    "unit": "u",
    "sampling_rate": 1000.0,
    "description": null,
    "measure": "measure_01",
    "source": "Test.v1",
  },
  {
    "label": "Fz",
    "name": "Channel Fz",
    "unit": "u",
    "sampling_rate": 1000.0,
    "description": null,
    "measure": "measure_01",
    "source": "Test.v1",
  }, ...]
  1. Define a list of channel names (channels).

  2. Call the post() method on the api.channel object using the await keyword.

  3. Provide a list comprehension that generates a dictionary for each channel containing the required information:

    • 'measure': A string representing the measurement name, which should match the measurement added earlier (in this case, ‘OpenBCI+EEG’).

    • 'name': A string representing the name of the channel.

    • 'unit': A string representing the unit of measurement for the channel (e.g., ‘µv’).

    • 'sampling_rate': A string representing the sample rate for the channel.

    • 'label': A string representing the label for the channel.

Retrieving channels

In this section, you will learn how to retrieve the channels using the TimescaleDB App API. This will enable you to access and manage the data streams associated with your projects, ensuring an organized and efficient data handling process.

[10]:
channel_retrieve = await api.channel.get({'source': 'Test.v1', 'measure': 'measure_01',})
JSON(channel_retrieve)

{
  "count": 16,
  "next": null,
  "previous": null,
  "results": [
    {
      "label": "Fp1",
      "name": "Channel Fp1",
      "unit": "u",
      "sampling_rate": 1000.0,
      "description": null,
      "measure": "measure_01",
      "source": "Test.v1",
    },
    {
      "label": "Fp2",
      "name": "Channel Fp2",
      "unit": "u",
      "sampling_rate": 1000.0,
      "description": null,
      "measure": "measure_01",
      "source": "Test.v1",
    },
    {
      "label": "F7",
      "name": "Channel F7",
      "unit": "u",
      "sampling_rate": 1000.0,
      "description": null,
      "measure": "measure_01",
      "source": "Test.v1",
    },
    {
      "label": "F3",
      "name": "Channel F3",
      "unit": "u",
      "sampling_rate": 1000.0,
      "description": null,
      "measure": "measure_01",
      "source": "Test.v1",
    },
    {
      "label": "Fz",
      "name": "Channel Fz",
      "unit": "u",
      "sampling_rate": 1000.0,
      "description": null,
      "measure": "measure_01",
      "source": "Test.v1",
    }, ...],
}
  1. Call the get() method on the api.channel object using the await keyword.

  2. The method returns a dictionary containing the list of channels and their details.

Posting time series data

Generating sample data

There are two ways to format data for creating time series. The first method involves specifying the channel name as a field in each data point. The data is organized as follows.

[10]:
samples = 1000
timestamps = np.linspace(0, 1, samples, endpoint=False).tolist()
values = np.random.normal(size=(16, samples)).tolist()

data = {
    'source': 'Test.v1',
    'measure': 'measure_01',
    'timestamps': timestamps,
    'values': {ch: v for ch, v in zip(channels_names, values)}
}

JSON(data)

{
  "source": "Test.v1",
  "measure": "measure_01",
  "timestamps": [0.0, 0.001, 0.002, 0.003, 0.004, ...],
  "values":
  {
    "Fp1": [0.34711817740090317, -1.373998424355547, -0.39322127871269436, -1.111255982165559, 0.06071957333582859, ...],
    "Fp2": [1.8096098166496126, -1.2539857896458793, 0.1374639333729667, -1.1122194147863311, 0.998832178431673, ...],
    "F7": [-0.8640874065862001, 2.002183201413598, -0.9489665863081633, 1.7407006351416718, -0.29351018590084604, ...],
    "F3": [0.3244570895718148, -0.2637354625262703, 0.6907490773128037, 0.17286084151369183, 0.47189173753588726, ...],
    "Fz": [0.4238299821121943, -0.5864728049174426, 1.5538433331843184, 0.07803548005715387, 0.2328274503324976, ...],
    "F4": [2.515569778569133, -1.8257571786363376, 0.8899724661428899, -0.34859854958655356, -1.479117072029477, ...],
    "F8": [0.34499142540188843, 0.6708567662879444, -0.6900725437146458, 1.2187313341259387, -0.26223811427805543, ...],
    "T7": [0.12259861061388816, 0.29032693757236416, 0.8579767470120819, 1.1341718127233447, -0.4441986636130705, ...],
    "T8": [1.0287494417306098, -0.36493261411934386, 1.7992826538502023, -0.12134496606248635, -1.048736262021584, ...],
    "P7": [-0.9265544082287746, 2.0764327480250686, -1.535105939481214, 0.5251835590865347, -0.7721224177960856, ...],
    "P3": [1.478853355483061, 0.20795725980813165, 0.31712269511931224, 1.0037525910639404, 0.46271685209749625, ...],
    "Pz": [-0.35696184370242023, 0.7350877497598095, 0.6033244498749512, -0.24181063419143817, -0.011128430023510785, ...],
    "P4": [-1.2999960440799223, -0.24273964370065604, -0.605244631100003, 0.041717947154476076, 0.1383329448640639, ...],
    "P8": [0.43299980528125254, 0.8929048609816086, 2.158369338006688, -0.015354090229645024, -0.16575765199640982, ...],
    "O1": [0.27728111172864345, 0.3881158749080788, 2.379831652393838, -0.23403314156046948, 0.40470302397155933, ...],
    "O2": [-0.9938377266631667, 1.0696414336042175, 1.323932992084977, 0.5441196655846727, -0.563596909795448, ...],
  },
}
[11]:
timeserie_response = await api.timeserie.post(data)
JSON(timeserie_response)

{
  "status": "success",
  "message": "Your data has been successfully saved.",
  "objects_created": 16000,
}
[12]:
samples = 100
timestamps = (np.linspace(0, 1, samples, endpoint=False)+29000).tolist()
values = np.random.normal(size=(16, samples)).tolist()

data = {
    'source': 'Test.v1',
    'measure': 'measure_01',
    'timestamps': timestamps,
    'values': {ch: v for ch, v in zip(channels_names, values)}
}

timeserie_response = await api.timeserie.post(data)
JSON(timeserie_response)

{
  "status": "success",
  "message": "Your data has been successfully saved.",
  "objects_created": 1600,
}
  1. Call the post() method on the api.timeserie object using the await keyword.

  2. Provide the generated data list as the first argument.

Retrieving time series statistical data

In this section, you will learn how to retrieve the statistical data of the time series using the TimescaleDB App API. This will allow you to analyze and visualize key metrics and patterns in your data, enhancing your project’s overall data-driven insights.

[13]:
timeserie_retrieve = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp1', 'Fp2', 'Fz'],
    'stats': 'true',
})
JSON(await api.next(timeserie_retrieve))

{
  "count": 1100,
  "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp1&channels=Fp2&channels=Fz&measure=measure_01&page=2&source=Test.v1&stats=true",
  "previous": null,
  "results":
  {
    "source": "Test.v1",
    "measure": "measure_01",
    "timestamps":
    {
      "tmin": 0.0,
      "tmax": 29000.23,
      "duration": 29000.23,
      "avg_diff_timestamp": 28348.22091886608,
      "std_diff_timestamp": 906218.3107073875,
      "max_diff_timestamp": 28999001.0,
      "min_diff_timestamp": 0.9999999999998899,
    },
    "values":
    {
      "Fp1":
      {
        "avg_value": 0.04235183800111286,
        "std_value": 0.9781944673402079,
        "max_value": 2.903569036502832,
        "min_value": -3.0079619604414725,
        "sum_value": 43.36828211313957,
      },
      "Fp2":
      {
        "avg_value": 0.03138705944890641,
        "std_value": 0.9889176671725225,
        "max_value": 3.69080684702923,
        "min_value": -4.01491434892373,
        "sum_value": 32.14034887568016,
      },
      "Fz":
      {
        "avg_value": 0.009271185085611531,
        "std_value": 1.008749488991178,
        "max_value": 2.867654021916618,
        "min_value": -3.328390420996595,
        "sum_value": 9.493693527666208,
      },
    },
  },
}
  1. Call the get() method on the api.timeserie object using the await keyword.

  2. By using stats: true, you are requesting basic statistical analysis for the specified channels.

  3. The method returns a dictionary containing the list of time series data and their details.

Retrieving time series data

In this section, you will learn how to retrieve time series data for selected channels using the TimescaleDB App API. This will enable you to access and analyze data from specific data streams, facilitating targeted insights and informed decision-making in your projects.

[14]:
timeserie_generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp1','Fp2','F7','F3','Fz','F4','F8']
})

JSON(await api.next(timeserie_retrieve))

{
  "count": 1100,
  "next": null,
  "previous": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp1&channels=Fp2&channels=Fz&measure=measure_01&source=Test.v1&stats=true",
  "results":
  {
    "source": "Test.v1",
    "measure": "measure_01",
    "timestamps":
    {
      "tmin": 29000.24,
      "tmax": 29000.99,
      "duration": 0.75,
      "avg_diff_timestamp": 10.0,
      "std_diff_timestamp": 1.8058451890815834e-09,
      "max_diff_timestamp": 10.000000002037268,
      "min_diff_timestamp": 9.99999999839929,
    },
    "values":
    {
      "Fp1":
      {
        "avg_value": 0.25731467837416433,
        "std_value": 0.9228684586765759,
        "max_value": 3.1892458615064903,
        "min_value": -1.541011875433074,
        "sum_value": 19.55591555643649,
      },
      "Fp2":
      {
        "avg_value": 0.23133370078140708,
        "std_value": 0.9708190315751954,
        "max_value": 2.818153192859766,
        "min_value": -1.7797516319097142,
        "sum_value": 17.581361259386938,
      },
      "Fz":
      {
        "avg_value": 0.11881919907619279,
        "std_value": 0.94929665499407,
        "max_value": 2.318342001711256,
        "min_value": -2.2342472142906664,
        "sum_value": 9.030259129790652,
      },
    },
  },
}
  1. Call the get() method on the api.timeserie object with a dictionary containing the desired channels and the number of data points to retrieve using the await keyword.

  2. The method returns an asynchronous iterator. Use the await anext() function to get the first element of the iterator.

  3. The method returns a dictionary containing the time series data for the specified channels.

Pagination and generator feature in the API

When the API returns a large number of results, it is often useful to paginate the data to improve the performance and manageability of the response. The API supports pagination and includes a next link in the response when there are more results available.

When the response includes a next link, the API will return a generator that you can use to iterate through the paginated results seamlessly. Using a generator allows you to fetch the subsequent pages of data on-demand, improving the efficiency of your application and reducing the amount of data loaded into memory at once.

To use the generator provided by the API, you can use the api.next() mrthod to retrieve the next result from the generator. Here’s an example of how you can use the generator to retrieve paginated results:

[15]:
generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp1','Fp2','F7','F3','Fz','F4','F8'],
    'page_size': 100,
})
try:
    page = 0
    while True:
        page += 1
        result = await api.next(generator)
        print(f"Page {page}: {len(result['results']['timestamps'])} samples")
        # Process the result
except StopAsyncIteration:
    pass
Page 1: 100 samples
Page 2: 100 samples
Page 3: 100 samples
Page 4: 100 samples
Page 5: 100 samples
Page 6: 100 samples
Page 7: 100 samples
Page 8: 100 samples
Page 9: 100 samples
Page 10: 100 samples
Page 11: 100 samples

In this example, the api.paginated_results.get() method returns a generator object based on the initial response, which includes the next link. The while loop iterates through the results, and the generator automatically fetches the next page of data when needed, allowing you to process the paginated data effortlessly. The loop will continue until a StopIteration exception is raised, indicating that there are no more results to process.

Batch size with POST requests

The POST request method in the TimeScaleDB RESTful API includes an optional argument called batch_size. This argument allows you to specify the number of records you want to process in a single batch when sending data to the API. By adjusting the batch size, you can optimize the performance and efficiency of your data transfer.

For instance, you can set the batch_size to 4 when posting time series data as follows:

[16]:
data1 = data.copy()
data1['timestamps'] = (np.array(data1['timestamps']) + 1).tolist()

data2 = data.copy()
data2['timestamps'] = (np.array(data2['timestamps']) + 2).tolist()

data3 = data.copy()
data3['timestamps'] = (np.array(data3['timestamps']) + 3).tolist()

timeserie_response = await api.timeserie.post([data1, data2, data3], batch_size=1)
JSON(timeserie_response)
[[
    {
      "status": "success",
      "message": "Your data has been successfully saved.",
      "objects_created": 1600,
    }], [
    {
      "status": "success",
      "message": "Your data has been successfully saved.",
      "objects_created": 1600,
    }], [
    {
      "status": "success",
      "message": "Your data has been successfully saved.",
      "objects_created": 1600,
    }]]

Upon successful submission, the timeserie_response will contain an array of dictionaries, each representing the status of a batch.

Batch size with GET requests (Parallel requests)

To handle multiple GET requests simultaneously, you can use parallel requests. This feature helps improve the performance of your API by processing multiple requests at once. Here’s an example of how to use the “Batch size” functionality with GET requests:

[17]:
timeserie = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp2'],
    'page_size': 4,
    'page': 1,
}, batch_size=2)

JSON(timeserie)
[
  {
    "count": 1200,
    "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&measure=measure_01&page=2&page_size=2&source=Test.v1",
    "previous": null,
    "results":
    {
      "source": "Test.v1",
      "measure": "measure_01",
      "timestamps": ["1970-01-01T00:00:00", "1970-01-01T00:00:00.001000"],
      "values":
      {
        "Fp2": [1.8096098166496126, -1.2539857896458793],
      },
    },
  },
  {
    "count": 1200,
    "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&measure=measure_01&page=3&page_size=2&source=Test.v1",
    "previous": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&measure=measure_01&page_size=2&source=Test.v1",
    "results":
    {
      "source": "Test.v1",
      "measure": "measure_01",
      "timestamps": ["1970-01-01T00:00:00.002000", "1970-01-01T00:00:00.003000"],
      "values":
      {
        "Fp2": [0.1374639333729667, -1.1122194147863311],
      },
    },
  }]

Optional time formats

The time argument can be set to “absolute”, “relative”, or “false”. The behavior changes depending on the value provided:

  1. absolute: Returns the time points as absolute datetime values.

  2. relative: Returns the time points as relative values in seconds.

  3. false: Omits the time points from the response.

[18]:
timeserie_generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp2', 'Fp1'],
    'page_size': 10,

    'timestamps': 'single absolute',
})
timeserie = await api.next(timeserie_generator)
JSON(timeserie)

{
  "count": 1200,
  "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&channels=Fp1&measure=measure_01&page=2&page_size=10&source=Test.v1&timestamps=single+absolute",
  "previous": null,
  "results":
  {
    "source": "Test.v1",
    "measure": "measure_01",
    "timestamps": ["1970-01-01T00:00:00", "1970-01-01T00:00:00.001000", "1970-01-01T00:00:00.002000", "1970-01-01T00:00:00.003000", "1970-01-01T00:00:00.004000", ...],
    "values":
    {
      "Fp2": [1.8096098166496126, -1.2539857896458793, 0.1374639333729667, -1.1122194147863311, 0.998832178431673, ...],
      "Fp1": [0.34711817740090317, -1.373998424355547, -0.39322127871269436, -1.111255982165559, 0.06071957333582859, ...],
    },
  },
}
[19]:
timeserie_generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp2'],
    'page_size': 10,

    'timestamps': 'relative',
})
timeserie = await api.next(timeserie_generator)
JSON(timeserie)

{
  "count": 1200,
  "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&measure=measure_01&page=2&page_size=10&source=Test.v1&timestamps=relative",
  "previous": null,
  "results":
  {
    "source": "Test.v1",
    "measure": "measure_01",
    "timestamps":
    {
      "Fp2": [0.0, 1.0, 2.0, 3.0, 4.0, ...],
    },
    "values":
    {
      "Fp2": [1.8096098166496126, -1.2539857896458793, 0.1374639333729667, -1.1122194147863311, 0.998832178431673, ...],
    },
  },
}
[20]:
timeserie_generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp2'],
    'page_size': 10,

    'timestamps': 'false',
})
timeserie = await api.next(timeserie_generator)
JSON(timeserie)

{
  "count": 1200,
  "next": "http://localhost:8000/timescaledbapp/timeserie/?channels=Fp2&measure=measure_01&page=2&page_size=10&source=Test.v1&timestamps=false",
  "previous": null,
  "results":
  {
    "source": "Test.v1",
    "measure": "measure_01",
    "timestamps": [],
    "values":
    {
      "Fp2": [1.8096098166496126, -1.2539857896458793, 0.1374639333729667, -1.1122194147863311, 0.998832178431673, ...],
    },
  },
}

The responses will have different time values depending on the time argument used:

  • With timestamps='absolute', the time points will be absolute datetime values.

  • With timestamps='relative', the time points will be relative values in seconds.

  • With timestamps='false', the time points will be omitted from the response.

  • With timestamps='single absolute', the time points will be absolute datetime values but only in the firts trial, the other ones will be empty.

  • With timestamps='single relative', the time points will be relative values in seconds but only in the firts trial, the other ones will be empty.

Utilizing the get_data function from the Dunderlab API

The script below uses the get_data function from the Dunderlab API to achieve the same goal as the code above. This function simplifies the process of reconstructing the data from the queried trials.

[21]:
from dunderlab.api.utils import get_data

timeserie_generator = await api.timeserie.get({
    'source': 'Test.v1',
    'measure': 'measure_01',
    'channels': ['Fp1', 'Fp2'],
    'page_size': 100,

    'timestamps': 'false',
})
timeserie = await api.next(timeserie_generator)
get_data(timeserie).shape
[21]:
(2, 100)
[ ]: