✨ Resumen

Primera versión del paquete climadiam para conectar con los servicios web del Subsistema de Climatología Ambiental (REDIAM). Permite consultar datos de estaciones meteorológicas de Andalucía de forma sencilla desde R.

🌍 Descripción general

El paquete permite conectarse al Subsistema CLIMA y facilita el acceso a datos meteorológicos y ambientales, incluyendo:

  • Estaciones, variables, magnitudes y unidades
  • Datos intradiarios, diarios, mensuales y anuales
  • Intervalos temporales y fechas específicas

🚀 Instalación y carga del paquete climadiam

# Instalar 'climadiam' desde GitHub solo si no está instalado
list.of.packages <- c("climadiam")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) remotes::install_github(paste0("mcorzot/",new.packages))
# Cargar el paquete
library(climadiam)

🔑 Acceso como usuario libre

user <- "usuario"
password <- "usuario"
idsesion <- getwsIDSesion(user, password)

🧩 Funcionalidades principales

  • Conexión a los servicios web del Subsistema CLIMA.
  • Consulta de tablas maestras: comarcas, provincias, redes, variables, estaciones.
  • Descarga de datos intradiarios, diarios y mensuales.
  • Obtención de intervalos temporales y fechas específicas.
  • Compatible con entornos RStudio y scripts automatizados.
  • En caso de realizar trabajos para la Junta de Andalucía o como socio de la Rediam, puede solicitar usuario avanzado.

📚 Ejemplos básicos de uso: lista de estaciones

estaciones <- getwsEstacionesList(idsesion)
head(estaciones)
##       ACLPKACL AGEPKAGE CESTACION COMPKCOM COORDENADAX COORDENADAY COORDENADAZ
## text1        9       14  RIA18101       29      443423     4114357         630
## text2        6       18     IQ097        7   569900.49  4183241.37        1018
## text3       13       17 RAIFJA016       39      506412     4240315         515
## text4       15       12    SIVA36       43      430997     4181855         530
## text5       23        6      6049       50   299922.22     4046728         517
## text6       11        8   RIA4119       52   238128.73  4156064.04          11
##                          DENOMINACION ENTORNO ESTAPKESTA      FECHAHORAPRO
## text1 IFAPA Centro Camino del Purchil    <NA>          1              <NA>
## text2                    Vélez-Blanco    <NA>          1              <NA>
## text3               Arroyo del Ojanco    <NA>          2              <NA>
## text4                 Avda. DE MADRID    <NA>          2 11/14/2025 8:30:0
## text5                     Genalguacil    <NA>          1              <NA>
## text6 IFAPA Centro Las Torres-Tomejil    <NA>          1              <NA>
##       FECHAHORAULTAGRE GESPKGES GRAFUBICACION LATITUD LONGITUD MODELO
## text1             <NA>      105          <NA>  37.172  -3.6385      A
## text2             <NA>      100          <NA>  37.792  -2.2073      A
## text3   8/8/2011 5:0:0      100          <NA>  38.309  -2.9279      A
## text4 5/22/2003 10:0:0        5          <NA> 37.7795  -3.7848      A
## text5 10/31/2001 0:0:0        5          <NA> 36.5431  -5.2364      P
## text6             <NA>      105          <NA> 37.5125   -5.964      A
##       MUNMUNICIPIO MUNPROVINCIA OBSERVACION OBSERVACIONADM PKEST PLUVIO
## text1           87           18        <NA>           <NA>  2865   <NA>
## text2           98            4        <NA>           <NA>  3458   <NA>
## text3          905           23        <NA>           <NA>  2892   <NA>
## text4           50           23        <NA>           <NA>  2280   <NA>
## text5           57           29        <NA>           <NA>   637   <NA>
## text6            5           41        <NA>           <NA>    89   <NA>
##       REDPKRED  WEB
## text1        5    S
## text2       31    S
## text3        6    S
## text4        3    S
## text5       28 <NA>
## text6        5    S

📚 Ejemplos básicos de uso: valor diario de una estación y variable

datos <- getwsDatosDiarios(idsesion, "EARM22", "TD1", "26/10/2025")
head(datos)
##   cestacion cvariable      fecha valor
## 1    EARM22       TD1 26/10/2025  20.7

📚 Ejemplo práctico de acceso a datos: selección de fechas, variables y estaciones

Obtención de fecha de ayer:

# Obtención de fecha a utilizar
date1 <- Sys.Date() - 1
date1_char <- format(date1, "%d/%m/%Y")
date1_char
## [1] "13/11/2025"

Obtención de fecha de antes de ayer:

# Obtención de fecha a utilizar
date2 <- Sys.Date() - 2
date2_char <- format(date2, "%d/%m/%Y")
date2_char
## [1] "12/11/2025"

Existencias de datos para la fecha de referencia (antes de ayer):

# Existencias de datos (tomando como referencia el día - 2)
existencias <- getwsDatosExisteEstacionesList(idsesion)
existencias$FECINICIODATOS <- as.Date(existencias$FECINICIODATOS)
existencias$FECFINDATOS <- as.Date(existencias$FECFINDATOS)
sel_existencias <- existencias[!is.na(existencias$CESTACION) & !is.na(existencias$FECINICIODATOS) & existencias$FECINICIODATOS < date2 & existencias$FECFINDATOS > date2, ]
head(sel_existencias[,c('CESTACION','FECINICIODATOS','FECFINDATOS')])
##      CESTACION FECINICIODATOS FECFINDATOS
## 231     SIVA26     1996-06-05  2025-11-13
## 262     SIVA28     1998-01-31  2025-11-13
## 304     SIVA30     1997-12-22  2025-11-13
## 451     SIVA40     1996-01-01  2025-11-13
## 462     SIVA41     1996-01-02  2025-11-13
## 1254 RAIFAL001     1995-12-31  2025-11-13

Estaciones (teniendo en cuenta existencias):

# Características básicas de las estaciones seleccionadas
estaciones     <- getwsEstacionesList(idsesion)
sel_estaciones <- estaciones[estaciones$CESTACION %in% sel_existencias$CESTACION, ]
head(sel_estaciones[,c('CESTACION','DENOMINACION','LATITUD','LONGITUD')])
##        CESTACION          DENOMINACION LATITUD LONGITUD
## text2     SIVA63      LAS FUENTEZUELAS 37.7844  -3.8103
## text4  RAIFMA006 Rincón de la Victoria 36.7128  -4.2488
## text11 RAIFJA003               Andújar 38.0339   -4.084
## text12 RAIFSE004            Isla Mayor 37.1771  -6.1806
## text13    SIVA51           SANTA CLARA 37.3981  -5.9514
## text23 RAIFSE008            El Saucejo 37.0731  -5.0902

Variables:

# Características de las variables seleccionadas
cvariables <- c("TI1", "PI1", "TD1", "TD2", "TD4","PD23")
variables <- data.frame()
for (cvariable in cvariables) {
  sel_variables <- getwsVariables(cvariable, idsesion)
  variables <- rbind(variables, sel_variables)
}
head(variables[,c('CVARIABLE','DENOMINACION')])
##       CVARIABLE                          DENOMINACION
## text        TI1 Temperatura media del termómetro seco
## text1       PI1     Precipitación caída en el período
## text2       TD1              Temperatura media diaria
## text3       TD2             Temperatura mínima diaria
## text4       TD4             Temperatura máxima diaria
## text5      PD23  Precipitación total diaria de 0 a 24

📚 Ejemplo práctico de acceso a datos intradiarios de ayer

Se usa la función “getwsDatosIntradiariosMulti” que requiere los identificadores de los parámetros de la consulta

# Parámetros de la función
# estaciones del dataframe "sel_estaciones"
cvariables_int <- c("TI1","HI1")
fechas_int <- date1_char

# Se fragmenta la consulta por red para evitar saturar el servicio
datos_intradiarios1 <- data.frame() # Se crea dataframe en blanco para almacenar los datos
for (i in 1:length(unique(sel_estaciones$REDPKRED))) {
  sel_estaciones_red <- sel_estaciones[sel_estaciones$REDPKRED == sel_estaciones$REDPKRED[i],]
  sel_cestaciones <- sel_estaciones_red$CESTACION
  sel_datos_intradiarios1 <- getwsDatosIntradiariosMulti(idsesion, sel_cestaciones, cvariables_int, fechas_int)
  datos_intradiarios1 <- rbind(datos_intradiarios1,sel_datos_intradiarios1)
}
head(datos_intradiarios1)
##   cestacion cvariable      fecha  hora valor
## 1    SIVA26       TI1 13/11/2025 00:00    17
## 2    SIVA26       TI1 13/11/2025 00:10    17
## 3    SIVA26       TI1 13/11/2025 00:20    17
## 4    SIVA26       TI1 13/11/2025 00:30    17
## 5    SIVA26       TI1 13/11/2025 00:40    17
## 6    SIVA26       TI1 13/11/2025 00:50    16

📚 Alternativa de acceso a datos intradiarios de ayer en caso de inestabilidad del servicio

Se usa la función “getwsDatosIntradiariosMultiRaw” que requiere los identificadores internos de los parámetros de la consulta

# Obtener identificadores internos de las variables intradiarias
cvariables_int <- c("TI1","HI1")
variables <- getwsVariablesList(idsesion) # lista de todas las variables
sel_variables <- variables[variables$CVARIABLE %in% cvariables_int,]
pkvars_int <- sel_variables$PKVAR

# Obtener identificadores internos de las fechas
date1      <- Sys.Date() - 1
date1_char <- format(date1, format = "%d/%m/%Y")
fechas <- getwsFechasList(idsesion) # lista de todas las fechas
fecha <- fechas[fechas$FECHA == date1_char,]
pkfec_int <- fecha$PKFEC
pkfec_int_prev <- as.numeric(fecha$PKFEC) - 1 # pkfec del día previo

# Obtener identificadores internos de las estaciones
estaciones <- getwsEstacionesList(idsesion) # lista de todas las estaciones
sel_estaciones <- estaciones[estaciones$CESTACION %in% sel_existencias$CESTACION, ]
# Se descartan las estaciones PART003 y CAHA01 dado que el servicio falla al devolver datos con
# intervalos de medida inferiores a 10 minutos
sel_estaciones <- sel_estaciones[sel_estaciones$CESTACION != "PART003", ]
sel_estaciones <- sel_estaciones[sel_estaciones$CESTACION != "CAHA01", ]

# Consulta con la función "getwsDatosIntradiariosMultiRaw" y los identificadores internos
# Se obtienen datos del día objetivo y el día previo ya que en CLIMA el dato del día 1 a las 00:00
# se almacena como el dato de las 24:00 del día anterior
# Se fragmenta la consulta por red para evitar saturar el servicio
datos_intradiarios1_alt <- data.frame() # Se crea dataframe en blanco para almacenar los datos
for (red in unique(sel_estaciones$REDPKRED)) {
  sel_estaciones_red <- subset(sel_estaciones, REDPKRED == red)
  sel_pkests    <- sel_estaciones_red$PKEST
  # Consulta día previo
  sel_datos_intradiarios1_alt_prev <- getwsDatosIntradiariosMultiRaw(idsesion,sel_pkests,pkvars_int,pkfec_int_prev)
  # Consulta día objetivo
  sel_datos_intradiarios1_alt <- getwsDatosIntradiariosMultiRaw(idsesion,sel_pkests,pkvars_int,pkfec_int)
  # Se anexan los resultados
  datos_intradiarios1_alt <- rbind(datos_intradiarios1_alt,sel_datos_intradiarios1_alt_prev,sel_datos_intradiarios1_alt)
}
head(datos_intradiarios1_alt)
##   pkest pkvar  pkfec minuto valor
## 1  2257     1 100758     NA    NA
## 2  2257     1 100758     NA    NA
## 3  2257     1 100758     NA    NA
## 4  2257     1 100758     NA    NA
## 5  2257     1 100758     NA    NA
## 6  2257     1 100758     60  16.4
# Se borran los registros en blanco derivados de la estructura de la respuesta del servicio
datos_intradiarios1_alt <- datos_intradiarios1_alt[complete.cases(datos_intradiarios1_alt), ]

# Obtenidos los datos en bruto, se relacionan con las tablas maestras
# Se relaciona con las horas-minutos
datos_intradiarios1_alt <- merge(x = datos_intradiarios1_alt, y = minutos_horas, by.x='minuto', by.y='MINUTOS')

# Se convierte el dato de las 24:00 en el de las 00:00 del dia siguiente
datos_intradiarios1_alt$HORA[datos_intradiarios1_alt$HORA=="24:00"] <- "00:00"
datos_intradiarios1_alt$pkfec <- ifelse(datos_intradiarios1_alt$HORA %in% "00:00", as.character(as.integer(datos_intradiarios1_alt$pkfec)+1), datos_intradiarios1_alt$pkfec)

# Se filtra teniendo en cuenta la fecha indicada en la consulta
datos_intradiarios1_alt <- datos_intradiarios1_alt[datos_intradiarios1_alt$pkfec %in% pkfec_int,]

# Se borran duplicados si los hubiera
datos_intradiarios1_alt <- datos_intradiarios1_alt[!duplicated(datos_intradiarios1_alt), ]

# Se ordena el dataframe por hora
datos_intradiarios1_alt <- datos_intradiarios1_alt[order(datos_intradiarios1_alt$pkest,datos_intradiarios1_alt$pkvar,datos_intradiarios1_alt$pkfec,datos_intradiarios1_alt$HORA),]

# Se asocian los identificadores internos con los valores aportados en la funcion
datos_intradiarios1_alt <- merge(x = datos_intradiarios1_alt, y = estaciones, by.x = 'pkest', by.y = 'PKEST')
datos_intradiarios1_alt <- merge(x = datos_intradiarios1_alt, y = variables, by.x = 'pkvar', by.y = 'PKVAR')
datos_intradiarios1_alt <- merge(x = datos_intradiarios1_alt, y = fechas, by.x = 'pkfec', by.y = 'PKFEC')

# Se compone el dataframe
datos_intradiarios1_alt <- data.frame(datos_intradiarios1_alt$CESTACION,datos_intradiarios1_alt$CVARIABLE,datos_intradiarios1_alt$FECHA,datos_intradiarios1_alt$HORA,datos_intradiarios1_alt$valor)
colnames(datos_intradiarios1_alt) <- c('cestacion','cvariable','fecha','hora','valor')
head(datos_intradiarios1_alt)
##   cestacion cvariable      fecha  hora valor
## 1    SIVA26       TI1 13/11/2025 00:00    17
## 2    SIVA26       TI1 13/11/2025 00:10    17
## 3    SIVA26       TI1 13/11/2025 00:20    17
## 4    SIVA26       TI1 13/11/2025 00:30    17
## 5    SIVA26       TI1 13/11/2025 00:40    17
## 6    SIVA26       TI1 13/11/2025 00:50    16

📚 Ejemplo práctico de acceso a datos diarios antes de ayer

Se usa la función “getwsDatosDiariosMulti” que requiere los identificadores de los parámetros de la consulta

# Datos diarios
cestaciones <- sel_existencias$CESTACION
cvariables_dia <- c("TD1","TD2","TD4","PD23")
fechas_dia <- date2_char
datos_diarios2 <- getwsDatosDiariosMulti(idsesion, cestaciones, cvariables_dia, fechas_dia)
head(datos_diarios2)
##   cestacion cvariable      fecha valor
## 1    SIVA26       TD1 12/11/2025  18.0
## 2    SIVA55       TD1 12/11/2025  18.3
## 3 RAIFAL011       TD1 12/11/2025  15.9
## 4 RAIFGR003       TD1 12/11/2025  17.5
## 5    SIVA30       TD1 12/11/2025  18.4
## 6    SIVA59       TD1 12/11/2025  20.5

📚 Alternativa de acceso a datos diarios antes de ayer

Se usa la función “getwsDatosDiariosMultiRaw” que requiere los identificadores internos de los parámetros de la consulta

# Obtener identificadores internos de las variables
cvariables_dia <- c("TD1","TD2","TD4","PD23")
variables <- getwsVariablesList(idsesion) # lista de todas las variables
sel_variables_dia <- variables[variables$CVARIABLE %in% cvariables_dia,]
pkvars_dia <- sel_variables_dia$PKVAR

# Obtener identificadores internos de las fechas
fechas_dia <- date2_char
date2_char <- format(date2, format = "%d/%m/%Y")
#fechas <- getwsFechasList(idsesion) # ejecutar sólo si no se hizo previamente
fecha <- fechas[fechas$FECHA == date2_char,]
pkfec_dia <- fecha$PKFEC

# Obtener identificadores internos de las estaciones
estaciones <- getwsEstacionesList(idsesion) # lista de estaciones
sel_estaciones <- estaciones[estaciones$CESTACION %in% sel_existencias$CESTACION, ]
# Se descartan las estaciones PART003 y CAHA01 dado que el servicio falla al devolver datos con
# intervalos de medida inferiores a 10 minutos
sel_estaciones <- sel_estaciones[sel_estaciones$CESTACION != "PART003", ]
sel_estaciones <- sel_estaciones[sel_estaciones$CESTACION != "CAHA01", ]

# Consulta con la función "getwsDatosDiariosMultiRaw" y los identificadores internos
# Fragmentar la consulta por red para evitar saturar el servicio
datos_diarios2_alt <- data.frame() # Se crea dataframe en blanco para almacenar los datos
for (red in unique(sel_estaciones$REDPKRED)) {
  sel_estaciones_red <- subset(sel_estaciones, REDPKRED == red)
  sel_pkests    <- sel_estaciones_red$PKEST
  # Consulta día objetivo
  sel_datos_diarios2_alt <- getwsDatosDiariosMultiRaw(idsesion,sel_pkests,pkvars_dia,pkfec_dia)
  # Se anexan los resultados
  datos_diarios2_alt <- rbind(datos_diarios2_alt,sel_datos_diarios2_alt)
}
head(datos_diarios2_alt)
##   pkest pkvar  pkfec valor
## 1  2254     5 100758  26.1
## 2  2254   711 100758   0.0
## 3  2254     3 100758  13.0
## 4  2254     2 100758  19.5
## 5  2191     5 100758  24.5
## 6  2191   711 100758   0.0
# Se ordena el dataframe por estación, variable y fecha
datos_diarios2_alt <- datos_diarios2_alt[order(datos_diarios2_alt$pkest,datos_diarios2_alt$pkvar,datos_diarios2_alt$pkfec),]

# Se asocian los identificadores internos con los valores aportados en la funcion
datos_diarios2_alt <- merge(x = datos_diarios2_alt, y = estaciones, by.x = 'pkest', by.y = 'PKEST')
datos_diarios2_alt <- merge(x = datos_diarios2_alt, y = variables, by.x = 'pkvar', by.y = 'PKVAR')
datos_diarios2_alt <- merge(x = datos_diarios2_alt, y = fechas, by.x = 'pkfec', by.y = 'PKFEC')

# Se compone el dataframe
datos_diarios2_alt <- data.frame(datos_diarios2_alt$CESTACION,datos_diarios2_alt$CVARIABLE,datos_diarios2_alt$FECHA,datos_diarios2_alt$valor)
colnames(datos_diarios2_alt) <- c('cestacion','cvariable','fecha','valor')
head(datos_diarios2_alt)
##   cestacion cvariable      fecha valor
## 1    SIVA26       TD1 12/11/2025  18.0
## 2    SIVA55       TD1 12/11/2025  18.3
## 3 RAIFAL011       TD1 12/11/2025  15.9
## 4 RAIFGR003       TD1 12/11/2025  17.5
## 5    SIVA30       TD1 12/11/2025  18.4
## 6    SIVA59       TD1 12/11/2025  20.5

📊 Visualización gráfica de datos intradiarios

# Selección de las cuatro primeras series y crear una columna de fecha-hora combinada
cestaciones_graph <- unique(datos_intradiarios1_alt$cestacion)[1:4]
datos_int <- datos_intradiarios1_alt %>%
  mutate(datetime = as.POSIXct(paste(fecha, hora), format = "%d/%m/%Y %H:%M")) %>%
  filter(cestacion %in% cestaciones_graph & cvariable %in% c("TI1", "HI1"))

# Crear el gráfico de temperaturas intradiarias por estación
ggplot(datos_int, aes(x = datetime, y = valor, color = cvariable, group = cvariable)) +
  geom_line(size = 1.2) +
  geom_point(size = 2) +
  facet_wrap(~ cestacion, scales = "free_y") +
  labs(
    title = "Evolución intradiaria de Temperatura (TI1) y Humedad (HI1)",
    x = "Fecha y hora",
    y = "Valor",
    color = "Variable"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "bottom"
  )

📊 Visualización gráfica de datos diarios

# Selección de datos de TD2
datos_dia <- datos_diarios2_alt[datos_diarios2_alt$cvariable == 'TD2',]
# Histograma de frecuencias de datos de temperatura diaria
ggplot(datos_dia, aes(x = valor)) +
  geom_histogram(binwidth = 1, fill = "#2b8cbe", color = "white", alpha = 0.8) +
  labs(
    title = "Distribución de valores de TD2",
    x = "Valor de TD2",
    y = "Frecuencia"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )


💻 Autoría y contacto

Desarrollado por mcorzot. Repositorio oficial: https://github.com/mcorzot/climadiam