Get data example#
This notebook shows how to use the get_data method to get data from the API.
API-24SEA endpoint: https://api.24sea.eu/routes/v1/datasignals/data
[1]:
# **Package Imports**
# - From the Python Standard Library
import logging
import os
import sys
# From third-party packages
import pandas as pd
# - API-24SEA
from api_24sea.version import __version__, parse_version
from api_24sea.datasignals.core import API
[2]:
# **Package Version**
print(f"Package {parse_version(__version__)}")
# **Notebook Configuration**
logger = logging.getLogger()
logger.setLevel(logging.WARNING)
Package Version(major=2, minor=1, patch=6, release=None, num=None)
Login Credentials
Do not store API credentials in plain text in your notebook. Rather use the python-dotenv package to load environment variables from a .env file.
[3]:
# **Set Sample API Credentials**
os.environ["API_24SEA_USERNAME"] = "Sample.User"
os.environ["API_24SEA_PASSWORD"] = "CheckOutSomeData!"
[4]:
# **Package Versions**
print("Working Folder: ", os.getcwd())
print(f"Python Version: {sys.version}")
print(f"Pandas Version: {pd.__version__}")
print(f"Package {parse_version(__version__)}")
# **Notebook Configuration**
logger = logging.getLogger()
logger.setLevel(logging.WARNING)
Working Folder: /home/pietro.dantuono@24SEA.local/Projects/API-24SEA/api-24sea-pkg/docs/project/user-manual/examples
Python Version: 3.13.1 (main, Jan 14 2025, 22:47:38) [Clang 19.1.6 ]
Pandas Version: 2.3.3
Package Version(major=2, minor=1, patch=6, release=None, num=None)
Accessing the data#
This example uses the synchronous pandas datasignals accessor. You can also use API directly, or AsyncAPI with await. All three use the same metric selection rules. The default result is a wide table indexed by timestamp, with full metric names as columns. The site and location dimensions are available in the metrics overview; they are not separate columns in this default result.
[ ]:
# Initialize the pandas accessor and inspect the authorized metrics.
df = pd.DataFrame()
m_o = df.datasignals.metrics_overview
assert m_o is not None, "Metrics overview is unavailable; check authentication."
# Use a site name from the overview. Sites and locations match full names or
# IDs case-insensitively; partial location names do not match.
site = "windfarm"
locations = (
m_o.loc[m_o["site"].str.lower() == site.lower(), "location"]
.drop_duplicates()
.tolist()
)
metrics = [
"mean windspeed", "mean power", "mean yaw", "mean rpm",
"mean pitch", "mean winddirection", "mean inc",
]
start_timestamp = "2020-03-01T00:00:00Z"
end_timestamp = "2020-06-01T00:00:00Z"
display(m_o[["metric", "statistic", "short_hand", "site", "location"]].head())
Understand the full metric names#
The selector searches ``m_o[“metric”]``, the full metric name, rather than the short_hand or description column. For example, a typical name is:
mean_WF_A01_windspeed
│ │ │ └─ short_hand: windspeed
│ │ └───── location_id: A01
│ └──────── site_id: WF
└───────────── statistic: mean
The general pattern is <statistic>_<site_id>_<location_id>_<short_hand>. The IDs can differ from the site and location display names. A short_hand may itself contain underscores, for example TP_INC_LAT015_DEG240_X_nr1. Always take the authoritative full name from the overview’s metric column; avoid assembling it from the display labels.
Choose selectors: spaces, underscores and regular expressions#
Matching is case-insensitive and uses a regular-expression search anywhere in the full name. The SDK first replaces every space and hyphen (-) with .* (zero or more characters), then joins a list of selectors with | (OR). An underscore (_) stays literal: it is not escaped or replaced and needs no backslash.
This distinction matters: "mean_windspeed" does not match mean_WF_A01_windspeed, because the IDs intervene. Use "mean windspeed" (which becomes mean.*windspeed) or r"^mean_.*_windspeed$" instead.
Selector |
What it searches for |
|---|---|
|
|
|
|
|
Names starting with |
|
That complete full name, case-insensitively. |
|
Names starting with |
^ means the start, $ the end, . any character, and * zero or more repetitions. (?:a|b) groups alternatives without capturing them, as in r"^mean_.*_(?:windspeed|power)$" for mean windspeed or power. The list ["mean windspeed", "mean power"] also means either selector can match. Raw strings (r"...") make backslashes easier to write: r"\d" matches a digit and r"\." a literal dot. Regex metacharacters are not automatically escaped. Space/hyphen replacement
also affects regex syntax, so use r"\d" or [0123456789] rather than a hyphenated range such as [0-9].
The Sample account may not include CC or MPE metrics. Preview the authorized matches below before launching a large request; no matches in get_data() raises DataSignalsError.
[ ]:
# Reproduce the SDK's selector normalization and preview the matching rows.
pattern = "|".join(
selector.replace(" ", ".*").replace("-", ".*")
for selector in metrics
)
location_names = [location.lower() for location in locations]
site_mask = (
m_o["site"].str.lower().eq(site.lower())
| m_o["site_id"].str.lower().eq(site.lower())
)
location_mask = (
m_o["location"].str.lower().isin(location_names)
| m_o["location_id"].str.lower().isin(location_names)
)
selected = m_o.loc[
site_mask & location_mask
& m_o["metric"].str.contains(pattern, case=False, regex=True),
["metric", "statistic", "short_hand", "site", "location"],
]
display(selected)
Retrieve the selection#
get_data() applies those selectors to the overview, then sends the matching full names to the API. Use metrics="all" to retrieve all authorized metrics at explicitly selected sites and locations; preview that selection using only site_mask & location_mask. To request one exact name, copy its metric value and anchor it with ^ and $, as shown above.
See the metric-selection guide for the complete matching rules, also used by statistics and availability queries.
[ ]:
data = df.datasignals.get_data(
site, locations, metrics, start_timestamp, end_timestamp,
)
display(data)
[6]:
# Extract data for a specific location only
display(data.datasignals.as_dict()[site][locations[0]])
display(data.datasignals.as_dict()[site][locations[1]])
| metric | mean_WF_A01_TP_INC_LAT015_DEG240_X_nr1 | mean_WF_A01_TP_INC_LAT015_DEG240_Y_nr2 | mean_WF_A01_pitch | mean_WF_A01_power | mean_WF_A01_rpm | mean_WF_A01_winddirection | mean_WF_A01_windspeed | mean_WF_A01_yaw |
|---|---|---|---|---|---|---|---|---|
| timestamp | ||||||||
| 2020-03-01 00:00:00+00:00 | 0.014474 | -0.136504 | 66.398788 | -41.469750 | 0.584501 | 49.649211 | 4.756602 | 154.942861 |
| 2020-03-01 00:10:00+00:00 | 0.014559 | -0.135702 | 66.398788 | -41.730277 | 0.415421 | 36.540062 | 3.286199 | 154.679861 |
| 2020-03-01 00:20:00+00:00 | 0.011589 | -0.130643 | 66.398788 | -41.638804 | 0.000000 | 48.983673 | 2.772254 | 118.406361 |
| 2020-03-01 00:30:00+00:00 | 0.010997 | -0.128664 | 66.398788 | -41.464462 | 0.000000 | 42.564542 | 3.068091 | 124.439561 |
| 2020-03-01 00:40:00+00:00 | 0.010591 | -0.129644 | 66.398788 | -41.569560 | 0.000000 | 45.848365 | 2.258143 | 132.942861 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2020-05-31 23:10:00+00:00 | 0.053218 | -0.236778 | 45.427588 | 204.217182 | 6.966832 | 197.925833 | 8.752479 | 87.034661 |
| 2020-05-31 23:20:00+00:00 | 0.061246 | -0.214491 | 50.685288 | 77.331198 | 5.043291 | 213.841401 | 9.028759 | 87.042861 |
| 2020-05-31 23:30:00+00:00 | 0.052135 | -0.240203 | 45.030288 | 230.445580 | 6.973209 | 260.730104 | 8.979204 | 84.818661 |
| 2020-05-31 23:40:00+00:00 | 0.052279 | -0.239876 | 45.145788 | 228.240668 | 6.983092 | 264.621709 | 8.812143 | 82.042861 |
| 2020-05-31 23:50:00+00:00 | 0.053963 | -0.235032 | 45.560188 | 164.459883 | 7.014018 | 258.697872 | 8.379906 | 82.012861 |
13248 rows × 8 columns
Both index and column named 'timestamp' found. Index takes precedence.
| metric | mean_WF_A02_TP_INC_LAT015_DEG240_X_nr1 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | mean_WF_A02_pitch | mean_WF_A02_power | mean_WF_A02_rpm | mean_WF_A02_winddirection | mean_WF_A02_windspeed | mean_WF_A02_yaw |
|---|---|---|---|---|---|---|---|---|
| timestamp | ||||||||
| 2020-03-01 00:00:00+00:00 | -0.006030 | -0.017105 | 66.398788 | -42.372609 | 0.000000 | 51.566748 | 4.418833 | 155.442861 |
| 2020-03-01 00:10:00+00:00 | -0.005865 | -0.016555 | 66.398788 | -43.083064 | 0.000000 | 35.673237 | 3.965547 | 141.050661 |
| 2020-03-01 00:20:00+00:00 | -0.006446 | -0.016817 | 66.398788 | -41.678109 | 0.000000 | 44.934812 | 2.456694 | 128.642861 |
| 2020-03-01 00:30:00+00:00 | -0.007844 | -0.018391 | 66.398788 | -41.820720 | 0.000000 | 37.605152 | 2.492990 | 128.642861 |
| 2020-03-01 00:40:00+00:00 | -0.008401 | -0.018518 | 66.398788 | -42.344867 | 0.000000 | 33.024645 | 2.127543 | 128.642861 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2020-05-31 23:10:00+00:00 | 0.046481 | -0.023932 | 45.233588 | 266.671847 | 7.006153 | 54.359444 | 8.840318 | 99.242861 |
| 2020-05-31 23:20:00+00:00 | 0.050933 | -0.027713 | 45.171388 | 284.882482 | 6.990850 | 211.905402 | 9.282334 | 91.005861 |
| 2020-05-31 23:30:00+00:00 | 0.056390 | -0.029176 | 45.070488 | 284.568935 | 6.970233 | 240.872527 | 9.040361 | 81.942861 |
| 2020-05-31 23:40:00+00:00 | 0.056814 | -0.024185 | 45.377088 | 228.474125 | 7.020075 | 241.614773 | 8.750821 | 79.985561 |
| 2020-05-31 23:50:00+00:00 | 0.052385 | -0.030792 | 44.765888 | 362.100604 | 6.971721 | 240.347007 | 9.856275 | 84.982061 |
13248 rows × 8 columns
Star Schema Format#
Data can be converted to a star schema format, where each metric’s name is converted to its “short_hand” from Metrics Overview, and the project and location columns are added as dimensions. The resulting DataFrame is indexed by timestamp and sorted by index.
[7]:
from api_24sea.datasignals.core import to_star_schema
start_schema = to_star_schema(df, metrics_overview=m_o)
data_ss = start_schema["FactPivotData"]
data_ss
Both index and column named 'timestamp' found. Index takes precedence.
[7]:
| timestamp | location | mean_TP_INC_LAT015_DEG240_X_nr1 | mean_TP_INC_LAT015_DEG240_Y_nr2 | mean_pitch | mean_power | mean_rpm | mean_winddirection | mean_windspeed | mean_yaw | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-03-01 00:00:00+00:00 | WFA01 | 0.014474 | -0.136504 | 66.398788 | -41.469750 | 0.584501 | 49.649211 | 4.756602 | 154.942861 |
| 1 | 2020-03-01 00:10:00+00:00 | WFA01 | 0.014559 | -0.135702 | 66.398788 | -41.730277 | 0.415421 | 36.540062 | 3.286199 | 154.679861 |
| 2 | 2020-03-01 00:20:00+00:00 | WFA01 | 0.011589 | -0.130643 | 66.398788 | -41.638804 | 0.000000 | 48.983673 | 2.772254 | 118.406361 |
| 3 | 2020-03-01 00:30:00+00:00 | WFA01 | 0.010997 | -0.128664 | 66.398788 | -41.464462 | 0.000000 | 42.564542 | 3.068091 | 124.439561 |
| 4 | 2020-03-01 00:40:00+00:00 | WFA01 | 0.010591 | -0.129644 | 66.398788 | -41.569560 | 0.000000 | 45.848365 | 2.258143 | 132.942861 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 26491 | 2020-05-31 23:10:00+00:00 | WFA02 | 0.046481 | -0.023932 | 45.233588 | 266.671847 | 7.006153 | 54.359444 | 8.840318 | 99.242861 |
| 26492 | 2020-05-31 23:20:00+00:00 | WFA02 | 0.050933 | -0.027713 | 45.171388 | 284.882482 | 6.990850 | 211.905402 | 9.282334 | 91.005861 |
| 26493 | 2020-05-31 23:30:00+00:00 | WFA02 | 0.056390 | -0.029176 | 45.070488 | 284.568935 | 6.970233 | 240.872527 | 9.040361 | 81.942861 |
| 26494 | 2020-05-31 23:40:00+00:00 | WFA02 | 0.056814 | -0.024185 | 45.377088 | 228.474125 | 7.020075 | 241.614773 | 8.750821 | 79.985561 |
| 26495 | 2020-05-31 23:50:00+00:00 | WFA02 | 0.052385 | -0.030792 | 44.765888 | 362.100604 | 6.971721 | 240.347007 | 9.856275 | 84.982061 |
26496 rows × 10 columns
[8]:
import matplotlib.colors as mcolors
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
from matplotlib.patches import Wedge
plt.rcParams.update({"axes.grid": False})
# Example plotting of the inclinations in the X and Y directions, with marginal
# histograms and alarm/warning levels.
def CustomCmap(from_rgb,to_rgb):
"""Create a custom colormap from two RGB tuples."""
r1, g1, b1 = from_rgb
r2, g2, b2 = to_rgb
cdict = {'red': ((0, r1, r1), (1, r2, r2)),
'green': ((0, g1, g1), (1, g2, g2)),
'blue': ((0, b1, b1), (1, b2, b2))}
cmap = mcolors.LinearSegmentedColormap('custom_cmap', cdict)
return cmap
# # ** Parameters **
MAIN_AXES_TITLE_FONT_SIZE = 10
TICK_LABEL_FONT_SIZE = 9
X_PARAMETER = "mean_TP_INC_LAT015_DEG240_X_nr1"
Y_PARAMETER = "mean_TP_INC_LAT015_DEG240_Y_nr2"
X_AXIS_TITLE = "Inclination X direction, deg"
Y_AXIS_TITLE = "Inclination Y direction, deg"
ALARM_LEVEL = 0.6
WARNING_LEVEL = 0.4
WARNING_WIDTH = ALARM_LEVEL - WARNING_LEVEL
LIM = ALARM_LEVEL * 1.1
# **Plotting**
fig2 = plt.figure(figsize=(7, 7), dpi=80)
# Define the grid layout
grid = plt.GridSpec(4, 4, hspace=0.4, wspace=0.6)
# Main plot (2D KDE)
main_ax = fig2.add_subplot(grid[1:4, 0:3])
# Marginal KDE plots
x_hist = fig2.add_subplot(grid[0, 0:3], sharex=main_ax);
y_hist = fig2.add_subplot(grid[1:4, 3], sharey=main_ax);
# Color settings
colors = ["lightseagreen", "orchid", "teal", "purple", "skyblue", "coral",
"gold", "darkkhaki", "lightcoral", "thistle", "lime", "darkorange",
"darkgreen", "deeppink", "navy"]
color_cycle = iter(colors)
legend_patches = []
for i, (location, group) in enumerate(data_ss.groupby("location")):
try:
color = next(color_cycle)
except StopIteration:
color_cycle = iter(colors)
color = next(color_cycle)
# 2D histogram on main_ax
rgb_color = mcolors.to_rgb(color)
light_rgb_color = tuple([c * 1 for c in rgb_color])
dark_rgb_color = tuple([c * 0.05 for c in rgb_color])
custom_cmap = CustomCmap(light_rgb_color, dark_rgb_color)
custom_cmap.set_under((1, 1, 1, 0))
h2d = main_ax.hist2d(group[X_PARAMETER], group[Y_PARAMETER], bins=120,
range=[[-LIM, LIM], [-LIM, LIM]], cmap=custom_cmap,
vmin=1, density=True)
# Marginal histogram for X axis
x_hist.hist(group[X_PARAMETER], bins=200, range=(-LIM, LIM), color=color,
alpha=0.8)
# Marginal histogram for Y axis (horizontal)
y_hist.hist(group[Y_PARAMETER], bins=200, range=(-LIM, LIM), color=color,
orientation='horizontal', alpha=0.8)
legend_patches.append(plt.Line2D([], [], color=color, lw=4, label=location))
# Draw alarm and warning levels
main_ax.add_patch(Wedge(center=(0, 0), r=ALARM_LEVEL, theta1=0, theta2=360,
width=WARNING_WIDTH, alpha=0.5, facecolor="goldenrod",
fill=True, linewidth=2, label='Warning Level'))
main_ax.add_patch(plt.Circle((0, 0), ALARM_LEVEL, edgecolor='firebrick',
alpha=0.9, fill=False, label="Alarm"))
x_hist.set_xlabel("");
y_hist.set_ylabel("");
# # Legend styling
legend = main_ax.legend(handles=legend_patches, loc="upper center",
title="Location", fontsize=TICK_LABEL_FONT_SIZE,
title_fontsize=10, frameon=True, facecolor="#F5F4EF",
edgecolor='#e4e8ee', bbox_to_anchor=(1.25, 1.4),
borderaxespad=0, labelspacing=0.7, handlelength=1.2,
borderpad=0.5, framealpha=0.8, fancybox=True,
shadow=False, ncol=6)
# Set legend font color
plt.setp(legend.get_texts(), color="#333333") # Labels in legend
plt.setp(legend.get_title(), color="#333333") # Title in legend
# Axis labels
main_ax.set_xlabel(X_AXIS_TITLE, fontsize=MAIN_AXES_TITLE_FONT_SIZE)
main_ax.set_ylabel(Y_AXIS_TITLE, fontsize=MAIN_AXES_TITLE_FONT_SIZE)
plt.show()
[ ]:
# Example plotting of the inclinations in the X and Y directions V. timestamp,
# and yaw as well as the power curve.
fig = plt.figure(figsize=(9, 7))
gs = fig.add_gridspec(19, 12)
ax1 = fig.add_subplot(gs[0:5, :])
ax2 = fig.add_subplot(gs[7:12, 0:5])
ax3 = fig.add_subplot(gs[7:12, 7:])
ax4 = fig.add_subplot(gs[14:, :])
FONT_SIZE = 9
# Inclination V. Timestamp
# Use Matplotlib's date conversion with its date locator/formatter.
# Pandas' plotting date units can differ from Matplotlib's across versions.
ax1.scatter(df["timestamp"], df["mean_WF_A01_TP_INC_LAT015_DEG240_X_nr1"],
color="turquoise", marker=".", label="X", s=2)
ax1.scatter(df["timestamp"], df["mean_WF_A01_TP_INC_LAT015_DEG240_Y_nr2"],
color="teal", marker=".", label="Y", s=2)
ax1.scatter(df["timestamp"], df["mean_WF_A02_TP_INC_LAT015_DEG240_X_nr1"],
color="orchid", marker="+", alpha=0.7, label="X", s=2)
ax1.scatter(df["timestamp"], df["mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2"],
color="purple", marker="+", alpha=0.7, label="Y", s=2)
ax1.legend(title="WFA01 WFA02", ncol=2, bbox_to_anchor=(0.15, 1.05),
fontsize=FONT_SIZE, title_fontsize=FONT_SIZE)
locator = mdates.AutoDateLocator(minticks=20, maxticks=26)
formatter = mdates.ConciseDateFormatter(locator)
ax1.xaxis.set_major_locator(locator)
ax1.xaxis.set_major_formatter(formatter)
ax1.set_xlabel("Timestamp", fontsize=FONT_SIZE)
ax1.set_ylabel("Inclination, °", fontsize=FONT_SIZE)
ax1.tick_params(labelsize=int(FONT_SIZE-1))
# Inclination V. Yaw
df.plot("mean_WF_A01_yaw", "mean_WF_A01_TP_INC_LAT015_DEG240_X_nr1",
kind="scatter", color="turquoise", marker=".", ax=ax2, s=2,
label= "WFA01")
df.plot("mean_WF_A02_yaw", "mean_WF_A02_TP_INC_LAT015_DEG240_X_nr1",
kind="scatter", color="orchid", marker="+", ax=ax2, alpha=0.5,
label="WFA02")
df.plot("mean_WF_A01_yaw", "mean_WF_A01_TP_INC_LAT015_DEG240_Y_nr2",
kind="scatter", color="teal", marker=".", ax=ax3, s=2,
label="WFA01")
df.plot("mean_WF_A02_yaw", "mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2",
kind="scatter", color="purple", marker="+", ax=ax3, alpha=0.5,
label="WFA02")
ax2.legend(loc="upper left", fontsize=FONT_SIZE)
ax2.set_xlabel("Yaw, °", fontsize=FONT_SIZE)
ax2.set_ylabel("X Inclination, °", fontsize=FONT_SIZE)
ax2.tick_params(labelsize=int(FONT_SIZE-1))
ax3.legend(loc="upper left", fontsize=FONT_SIZE)
ax3.set_xlabel("Yaw, °", fontsize=FONT_SIZE)
ax3.set_ylabel("Y Inclination, °", fontsize=FONT_SIZE)
ax3.tick_params(labelsize=int(FONT_SIZE-1))
# Power V. Windspeed
df.plot("mean_WF_A01_windspeed", "mean_WF_A01_power",
kind="scatter", color="teal", marker=".", ax=ax4, s=2,
label="WFA01")
df.plot("mean_WF_A02_windspeed", "mean_WF_A02_power",
kind="scatter", color="purple", marker="+", ax=ax4, alpha=0.5,
label="WFA02")
ax4.legend(loc="upper left", fontsize=FONT_SIZE)
ax4.set_xlabel("Windspeed, m/s", fontsize=FONT_SIZE)
ax4.set_ylabel("Power, kW", fontsize=FONT_SIZE)
ax4.tick_params(labelsize=int(FONT_SIZE-1))
plt.show()
Category-Value Format#
Data can also be converted to a category-value format, where each metric is converted to a “category” column containing the metric name, and a “value” column containing the metric value. The site and location columns are added as dimensions. The resulting DataFrame is indexed by timestamp and sorted by index.
[10]:
from api_24sea.datasignals.core import to_category_value
data_cv = to_category_value(df, df.datasignals.selected_metrics.reset_index())
data_cv
Both index and column named 'timestamp' found. Index takes precedence.
/home/pietro.dantuono@24SEA.local/Projects/API-24SEA/api-24sea-pkg/api_24sea/datasignals/core.py:1675: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
.bfill(axis=1)
[10]:
| timestamp | metric | value | unit | statistic | short_hand | site_id | location_id | sub_assembly | lat | heading | site | location | metric_group | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-03-01 00:00:00+00:00 | mean_WF_A01_pitch | 66.398788 | ° | mean | pitch | WF | A01 | NaN | NaN | NaN | WindFarm | WFA01 | scada |
| 1 | 2020-03-01 00:10:00+00:00 | mean_WF_A01_pitch | 66.398788 | ° | mean | pitch | WF | A01 | NaN | NaN | NaN | WindFarm | WFA01 | scada |
| 2 | 2020-03-01 00:20:00+00:00 | mean_WF_A01_pitch | 66.398788 | ° | mean | pitch | WF | A01 | NaN | NaN | NaN | WindFarm | WFA01 | scada |
| 3 | 2020-03-01 00:30:00+00:00 | mean_WF_A01_pitch | 66.398788 | ° | mean | pitch | WF | A01 | NaN | NaN | NaN | WindFarm | WFA01 | scada |
| 4 | 2020-03-01 00:40:00+00:00 | mean_WF_A01_pitch | 66.398788 | ° | mean | pitch | WF | A01 | NaN | NaN | NaN | WindFarm | WFA01 | scada |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 211963 | 2020-05-31 23:10:00+00:00 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | -0.023932 | ° | mean | TP_INC_LAT015_DEG240_Y_nr2 | WF | A02 | TP | 15.0 | 240.0 | WindFarm | WFA02 | inclination |
| 211964 | 2020-05-31 23:20:00+00:00 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | -0.027713 | ° | mean | TP_INC_LAT015_DEG240_Y_nr2 | WF | A02 | TP | 15.0 | 240.0 | WindFarm | WFA02 | inclination |
| 211965 | 2020-05-31 23:30:00+00:00 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | -0.029176 | ° | mean | TP_INC_LAT015_DEG240_Y_nr2 | WF | A02 | TP | 15.0 | 240.0 | WindFarm | WFA02 | inclination |
| 211966 | 2020-05-31 23:40:00+00:00 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | -0.024185 | ° | mean | TP_INC_LAT015_DEG240_Y_nr2 | WF | A02 | TP | 15.0 | 240.0 | WindFarm | WFA02 | inclination |
| 211967 | 2020-05-31 23:50:00+00:00 | mean_WF_A02_TP_INC_LAT015_DEG240_Y_nr2 | -0.030792 | ° | mean | TP_INC_LAT015_DEG240_Y_nr2 | WF | A02 | TP | 15.0 | 240.0 | WindFarm | WFA02 | inclination |
211968 rows × 14 columns