{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multivariate Time Series\n",
    "\n",
    "When you have multiple signals that share the same timestamps — like wind, solar, and hydro power — use `TimeSeriesTable` (also aliased as `MultivariateTimeSeries`). It stores per-column metadata and a 2D numpy array of values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "from datetime import datetime, timedelta, timezone\n\nimport numpy as np\n\nimport timedatamodel as tdm\n\nbase = datetime(2024, 1, 15, tzinfo=timezone.utc)\ntimestamps = [base + timedelta(hours=i) for i in range(24)]"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating a TimeSeriesTable\n",
    "\n",
    "Pass a 2D array (rows = timestamps, columns = variables) along with per-column metadata."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "rng = np.random.default_rng(42)\n\nwind = 80 + 40 * np.sin(np.linspace(0, 2 * np.pi, 24)) + rng.normal(0, 5, 24)\nsolar = np.clip(60 * np.sin(np.linspace(-0.5, np.pi + 0.5, 24)), 0, None) + rng.normal(0, 2, 24)\nsolar = np.clip(solar, 0, None)\nhydro = 50 + rng.normal(0, 3, 24)\n\nvalues = np.column_stack([wind, solar, hydro])\n\ntable = tdm.TimeSeriesTable(\n    tdm.Frequency.PT1H,\n    timezone=\"UTC\",\n    timestamps=timestamps,\n    values=values,\n    names=[\"wind\", \"solar\", \"hydro\"],\n    units=[\"MW\", \"MW\", \"MW\"],\n    data_types=[tdm.DataType.OBSERVATION, tdm.DataType.OBSERVATION, tdm.DataType.OBSERVATION],\n)\ntable"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspecting table properties"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"Columns:     {table.column_names}\")\n",
    "print(f\"Shape:       ({len(table)}, {table.n_columns})\")\n",
    "print(f\"Begin:       {table.begin}\")\n",
    "print(f\"End:         {table.end}\")\n",
    "print(f\"Has missing: {table.has_missing}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Selecting a single column\n",
    "\n",
    "`select_column()` extracts one column as a univariate `TimeSeriesList`, carrying over its metadata."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts_wind = table.select_column(\"wind\")\n",
    "ts_wind"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts_solar = table.select_column(\"solar\")\n",
    "print(f\"Name: {ts_solar.name}, Unit: {ts_solar.unit}, Data type: {ts_solar.data_type}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Merging univariate series into a table\n",
    "\n",
    "`TimeSeriesList.merge()` is the reverse operation — combine several univariate series that share the same timestamps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "ts_a = tdm.TimeSeriesList(\n    tdm.Frequency.PT1H,\n    timestamps=timestamps,\n    values=wind.tolist(),\n    name=\"wind\",\n    unit=\"MW\",\n)\nts_b = tdm.TimeSeriesList(\n    tdm.Frequency.PT1H,\n    timestamps=timestamps,\n    values=solar.tolist(),\n    name=\"solar\",\n    unit=\"MW\",\n)\nts_c = tdm.TimeSeriesList(\n    tdm.Frequency.PT1H,\n    timestamps=timestamps,\n    values=hydro.tolist(),\n    name=\"hydro\",\n    unit=\"MW\",\n)\n\nmerged = tdm.TimeSeriesList.merge([ts_a, ts_b, ts_c])\nmerged"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Decomposing a table back to univariate series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "univariate_list = merged.to_univariate_list()\n",
    "for ts in univariate_list:\n",
    "    print(f\"{ts.name}: {len(ts)} points, unit={ts.unit}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Table arithmetic\n",
    "\n",
    "Scalar arithmetic works on all columns simultaneously."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "table_gw = table * 0.001\n",
    "table_gw.head(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Iteration and indexing\n",
    "\n",
    "Each row is a `(timestamp, [values...])` tuple."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts_val, row_vals = table[0]\n",
    "print(f\"Timestamp: {ts_val}\")\n",
    "print(f\"Values:    {row_vals}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for ts_val, row_vals in table.head(4):\n",
    "    wind_mw, solar_mw, hydro_mw = row_vals\n",
    "    print(f\"{ts_val:%Y-%m-%d %H:%M}  wind={wind_mw:6.1f}  solar={solar_mw:5.1f}  hydro={hydro_mw:5.1f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conversion to pandas DataFrame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = table.to_pandas_dataframe()\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Summary\n\n- `TimeSeriesTable` stores multiple aligned columns with per-column metadata\n- `select_column()` extracts a single column as a `TimeSeriesList`\n- `TimeSeriesList.merge()` combines univariate series into a table\n- `to_univariate_list()` decomposes a table back to individual series\n- Scalar arithmetic applies across all columns\n\nNext up: **nb_06** covers `TimeSeriesArray` and `TimeSeriesCollection` for higher-dimensional data."
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}