Skip to content

Compare Sensors

This example demonstrates how to compare daily mean values from two different sensors (plots) using R. It retrieves data for a specified variable and date range, processes it, and generates a line chart comparing the two sensors.

ICP Documentation

In this example, we will compare air temperature (code_variable = 'AT') data from two different plots (code_plot = '1203' and '1204') over the year 2023.

You can request data from the mm_mem table in the icp_download schema. The data is filtered by the date_observation column, which is a date type representing the date (YYYY-MM-DD) of the observation.

Script

Environment Variable

Do not forget to create a .env file in the same directory as the R script including your API key.

If you do not have an API key yet, please see Getting Started

R
# Compare data from two sensors by charting daily mean values over time

# Load necessary libraries
library(httr)
library(ggplot2)

# Configuration
data_schema <- 'icp_download'
dictionaries_schema <- 'icp_dictionaries'

table <- 'mm_mem'
host <- 'https://db.forstliche-umweltkontrolle.de/' # Supabase host
apikey <- '[apikey]'

start_date_observation <- '2023-01-01'
end_date_observation <- '2023-12-31'

code_variable <- 'AT' # e.g. AT, NR, TF https://icp-forests.org/documentation/Dictionaries/d_variable.html

code_plot_1 <- '1203' # Plot number 1
code_plot_2 <- '1204' # Plot number 2

# Function to fetch data by plot, variable, and date range
fetch_data <- function(schema, table, host, apikey, code_plot, code_variable, start_date, end_date) {
    url <- paste0(host, "rest/v1/", table,
        "?date_observation=gte.", start_date,
        "&date_observation=lte.", end_date,
        "&code_variable=eq.", code_variable,
        "&code_plot=eq.", code_plot,
        "&select=daily_mean,date_observation,code_variable,code_plot,daily_min,daily_max,instrument_seq_nr"
    )
    # Accept-Profile header to specify schema

    response <- httr::GET(url, httr::add_headers(
        apikey = apikey,
        Authorization = paste("Bearer", apikey),
        `Accept-Profile` = schema,
        `Accept` = 'text/csv'
    ))
  
    if (response$status_code != 200) {
        stop("Failed to fetch data: ", response$status_code, " - ", httr::content(response, as = "text"))
    }
    data <- httr::content(response, as = "parsed", type = "text/csv", encoding = "UTF-8")
    return(data)
}

# Fetch data
data_1 <- fetch_data(data_schema, table, host, apikey, code_plot_1, code_variable, start_date_observation, end_date_observation)
data_2 <- fetch_data(data_schema, table, host, apikey, code_plot_2, code_variable, start_date_observation, end_date_observation)


# Get description and unit from icp_dictionaries.d_variable by code_variable
fetch_variable_info <- function(schema, host, apikey, code_variable) {

    url <- paste0(host, "rest/v1/d_variable?code=eq.", code_variable, "&select=description,unit")

    response <- httr::GET(url, httr::add_headers(
        apikey = apikey,
        Authorization = paste("Bearer", apikey),
        `Accept-Profile` = schema,
        `Accept` = 'application/json'
    ))
  
    if (response$status_code != 200) {
        stop("Failed to fetch variable info: ", response$status_code, " - ", httr::content(response, as = "text"))
    }
    info <- httr::content(response, as = "parsed", type = "application/json", encoding = "UTF-8")
    return(info[[1]])
}
variable_info <- fetch_variable_info(dictionaries_schema, host, apikey, code_variable)
variable_description <- variable_info$description # e.g., "Air Temperature"
variable_unit <- variable_info$unit # e.g., "°C"

## Plot linechart comparing daily mean values from both sensors
data_1$code_plot <- as.factor(data_1$code_plot)
data_2$code_plot <- as.factor(data_2$code_plot)

# Create the plot
ggplot() +
    geom_line(data = data_1, aes(x = as.Date(date_observation), y = daily_mean, color = code_plot), size = 1) +
    geom_line(data = data_2, aes(x = as.Date(date_observation), y = daily_mean, color = code_plot), size = 1) +
    labs(title = paste("Comparison of sensors example"),
         x = "Date",
         y = paste("Daily Mean", variable_description, "(", variable_unit, ")"),
         color = "Plot Number") +
    scale_color_manual(values = c("1203" = "blue", "1204" = "red")) +
    theme_minimal() +
    theme(text = element_text(size = 16))

# Get the directory of the current R script
script_dir <- dirname(sys.frames()[[1]]$ofile)

# Save the plot in the same directory as the R script
ggsave(file.path(script_dir, "compare_sensors.png"), width = 16, height = 9, units = "in")
Python
import requests
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
import os
import io

# Configuration
data_schema = "icp_download"
dictionaries_schema = "icp_dictionaries"

table = "mm_mem"
host = "https://db.forstliche-umweltkontrolle.de/"  # Supabase host
apikey = "[apikey]"

start_date_observation = "2023-01-01"
end_date_observation = "2023-12-31"

code_variable = "AT"  # e.g., AT, NR, TF
code_plot_1 = "1203"  # Plot number 1
code_plot_2 = "1204"  # Plot number 2

# Function to fetch data by plot, variable, and date range
def fetch_data(schema, table, host, apikey, code_plot, code_variable, start_date, end_date):
    url = f"{host}rest/v1/{table}"
    # Postgrest query parameters
    params = {
        ("date_observation", f"gte.{start_date}"),
        ("date_observation", f"lte.{end_date}"),
        ("code_variable", f"eq.{code_variable}"),
        ("code_plot", f"eq.{code_plot}"),
        ("select", "daily_mean,date_observation,code_variable,code_plot,daily_min,daily_max,instrument_seq_nr")
    }
    headers = {
        "apikey": apikey,
        "Authorization": f"Bearer {apikey}",
        "Accept-Profile": schema,
        "Accept": "text/csv"
    }
    response = requests.get(url, headers=headers, params=params)
    if response.status_code != 200:
        raise Exception(f"Failed to fetch data: {response.status_code} - {response.text}")
    data = pd.read_csv(io.StringIO(response.text))  # Use io.StringIO here
    return data

# Fetch data
data_1 = fetch_data(data_schema, table, host, apikey, code_plot_1, code_variable, start_date_observation, end_date_observation)
data_2 = fetch_data(data_schema, table, host, apikey, code_plot_2, code_variable, start_date_observation, end_date_observation)

# Sort data by date_observation
data_1 = data_1.sort_values(by="date_observation")
data_2 = data_2.sort_values(by="date_observation")


# Function to fetch variable info
def fetch_variable_info(schema, host, apikey, code_variable):
    url = f"{host}rest/v1/d_variable"
    params = {
        "code": f"eq.{code_variable}",
        "select": "description,unit"
    }
    headers = {
        "apikey": apikey,
        "Authorization": f"Bearer {apikey}",
        "Accept-Profile": schema,
        "Accept": "application/json"
    }
    response = requests.get(url, headers=headers, params=params)
    if response.status_code != 200:
        raise Exception(f"Failed to fetch variable info: {response.status_code} - {response.text}")
    info = response.json()
    return info[0]

variable_info = fetch_variable_info(dictionaries_schema, host, apikey, code_variable)
variable_description = variable_info["description"]  # e.g., "Air Temperature"
variable_unit = variable_info["unit"]  # e.g., "°C"

# Convert date_observation to datetime
data_1["date_observation"] = pd.to_datetime(data_1["date_observation"])
data_2["date_observation"] = pd.to_datetime(data_2["date_observation"])

# Plot line chart comparing daily mean values from both sensors
plt.figure(figsize=(16, 9))
plt.plot(data_1["date_observation"], data_1["daily_mean"], label="Plot 1203", color="blue", linewidth=2)
plt.plot(data_2["date_observation"], data_2["daily_mean"], label="Plot 1204", color="red", linewidth=2)

plt.title("Comparison of Sensors Example", fontsize=16)
plt.xlabel("Date", fontsize=14)
plt.ylabel(f"Daily Mean {variable_description} ({variable_unit})", fontsize=14)
plt.legend(title="Plot Number", fontsize=12)
plt.grid(True)

# Save the plot in the same directory as the script
script_dir = os.path.dirname(os.path.abspath(__file__))
plt.savefig(os.path.join(script_dir, "compare_sensors_py.png"), dpi=300)
#plt.show()
bash
API_KEY=[your_api_key]

Output

The output is a line chart comparing the daily mean values of the specified variable from two different sensors (plots) over the selected date range. The chart includes a title, labeled axes, and a legend indicating the plot numbers.