Skip to article frontmatterSkip to article content

Estaciones hidrometeorológicas

Estaciones hidrometeorológicas


Introducción

En este cuadernillo (Notebook) aprenderemos:

  1. Introduccion a la red de monitoreo del IDEAM
  2. Cátalogo de estaciones de IDEAM
  3. Consulta de datos usando la plataforma datosabiertos.gov.co
  4. Consulta de datos de temperatura y precipitación
  5. Otros datos disponibles

Prerequisitos

ConceptosImportanciaNotas
Introducción a PandasNecesarioLectura de datos tabulares
Introducción a DatetimeNecesarioEntender estampas de tiempo
Introducción a CartopyNecesarioEntender estampas de tiempo
Introducción a foliumÚtilMapas interactivos
  • Tiempo de aprendizaje: 30 minutos

1. Catálogo nacional de estaciones de IDEAM

Según el catálogo de estaciones hidrometeorológicas del IDEAM, el país cuenta con alrededor de 4.400 estaciones de diferentes categorías. En el siguiente cuadro se resume el estado de las estaciones por categoría de acuerdo a la PQR No. 20229050190832 (Enero de 2023)

CategoríaActivaMantenimientoSuspendidas
Limnográfica287109106
Climátologica principal2156092
Mareográfica422
Pluviográfica104087
Limnométrica32311557
Climática Ordinaria21131253
Agrometeorológica51457
Radio Sonda622
Pluviométrica11099603
Meteorológica Especial40468
Sinóptica Principal2734
Sinóptica Secundaria205
Total23812351866

Librerías

A continuación vamos a importar las librerías que utilizaremos en este cuadernillo.

from datetime import datetime, timedelta

import cartopy.crs as ccrs
import cartopy.feature as feature
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.dates import DateFormatter, HourLocator
from pandas import to_datetime
from sodapy import Socrata

2. Acceso al catálogo en bart.ideam.gov.co

El catálogo nacional de estaciones del IDEAM actualizado se encuentra disponible en el servidor Bart. Podemos leer el catálogo usando pandas.read_excel como se muestra a continuación:

client = Socrata("www.datos.gov.co", None)
results = client.get("hp9r-jxuu", limit=10000)

# Convert to pandas DataFrame
df_cat = pd.DataFrame.from_records(results)
WARNING:root:Requests made without an app_token will be subject to strict throttling limits.
df_cat["latitud"] = df_cat["ubicaci_n"].apply(lambda d: float(d["latitude"]))
df_cat["longitud"] = df_cat["ubicaci_n"].apply(lambda d: float(d["longitude"]))
df_cat.head()
Loading...
df_cat["estado"].str.lower() 
0 activa 1 activa 2 activa 3 activa 4 activa ... 8968 activa 8969 activa 8970 activa 8971 activa 8972 activa Name: estado, Length: 8973, dtype: object
filtered_df = df_cat[
    (df_cat["entidad"].str.lower()  == "ideam") &
    (df_cat["estado"].str.lower() == "activa")
]
filtered_df
Loading...

2.1 Mapa de estaciones

Podemos usar cartopy para hacer un mapa y visualizar las estaciones de monitoreo en el país

fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()}, dpi=150)
ax.coastlines()
gl = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree())
ax.scatter(df_cat["longitud"], df_cat["latitud"], transform=ccrs.PlateCarree(), s=0.5)
ax.add_feature(feature.LAND)
ax.add_feature(feature.OCEAN)
ax.add_feature(feature.COASTLINE, linewidth=0.5)
ax.add_feature(feature.BORDERS, linewidth=0.5)
<cartopy.mpl.feature_artist.FeatureArtist at 0x7f79764220c0>
/home/runner/micromamba/envs/cdh-python/lib/python3.12/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/runner/micromamba/envs/cdh-python/lib/python3.12/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_ocean.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/runner/micromamba/envs/cdh-python/lib/python3.12/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_coastline.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/runner/micromamba/envs/cdh-python/lib/python3.12/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_cultural/ne_50m_admin_0_boundary_lines_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
<Figure size 960x720 with 1 Axes>

podemos agrupar la data por área operativa, tipo de estación, tecnología, y otras variables

df_grp = df_cat.groupby("estado")
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()}, dpi=150)

for _, group in df_grp:
    ax.scatter(
        group["longitud"],
        group["latitud"],
        transform=ccrs.PlateCarree(),
        s=0.5,
        label=_,
    )

ax.coastlines()
gl = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree())
ax.add_feature(feature.LAND)
ax.add_feature(feature.OCEAN)
ax.add_feature(feature.COASTLINE, linewidth=0.5)
ax.add_feature(feature.BORDERS, linewidth=0.5)
ax.legend(fontsize=5)
<Figure size 960x720 with 1 Axes>
# df_grp = df_cat.groupby("entidad")
# fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()}, dpi=150)

# for _, group in df_grp:
#     ax.scatter(
#         group["longitud"],
#         group["latitud"],
#         transform=ccrs.PlateCarree(),
#         s=0.5,
#         label=_,
#     )

# ax.coastlines()
# gl = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree())
# ax.add_feature(feature.LAND)
# ax.add_feature(feature.OCEAN)
# ax.add_feature(feature.COASTLINE, linewidth=0.5)
# ax.add_feature(feature.BORDERS, linewidth=0.5)
# ax.legend(fontsize=5)

Podemos validar el número total de estaciones activas, en matenimiento y suspendidas de acuerdo con la información contenida en el catálogo

for grp in df_grp.groups.keys():
    print(f"{grp}: {len(df_grp.get_group(grp))}")
Activa: 5491
En Mantenimiento: 43
Suspendida: 3439

2.2 Mapa de estaciones interactivo

También podemos hacer mapas interactivos usando folium

import folium
from folium import plugins
from folium.plugins import MarkerCluster
min_lon, max_lon, min_lat, max_lat = -90, -72, -1, 14

map_ = folium.Map(
    location=[8, -76],
    zoom_start=6,
    min_lat=min_lat,
    max_lat=max_lat,
    min_lon=min_lon,
    max_lon=max_lon,
    zoom_control=False,
    control_scale=True,
    scrollWheelZoom=True,
    width=1000,
    height=600,
)
marker_cluster = MarkerCluster(name="Estaciones").add_to(map_)

folium.TileLayer("cartodbpositron").add_to(map_)
folium.TileLayer("openstreetmap").add_to(map_)
folium.TileLayer("cartodbdark_matter").add_to(map_)
folium.LayerControl().add_to(map_)

minimap = plugins.MiniMap()
_ = map_.add_child(minimap)

Ahora agregamos las estaciones usando la siguiente función:

def plot_station(row):
    """input: series that contains a numeric named latitude and a numeric named longitude
    this function creates a CircleMarker and adds it to your this_map"""

    html = row.to_frame("_").to_html(
        classes="table table-striped table-hover table-condensed table-responsive"
    )
    popup = folium.Popup(html, max_width=2650)
    folium.Marker(location=[row.latitud, row.longitud], popup=popup).add_to(
        marker_cluster
    )
df_cat.apply(plot_station, axis=1)
map_
Loading...

3. Acceso a la información histórica de IDEAM usando datosabiertos.gov.co

la información histórica de múltiples sensores se puede consultar a través de la plataforma de datos abiertos usando el aplicativo sodapy. Socrata utiliza un módulo denominado Socrata que permite realizar consultas al repositorio. Cada variable hidrometeorógica dispuesta se puede consultar usando el su respectivo código del set de datos.

VariableCódigo del set de datos
Dirección del vientokiw7-v9ta
Nivel instantáneobdmn-sqnh
Temperatura Mínima del Aireafdg-3zpb
Temperatura Máxima del Aireccvq-rp9s
Velocidad del Vientosgfv-3yp8
Nivel Máximovfth-yucv
Nivel Mínimopt9a-aamx
Humedad del Aireuext-mhny
Temperaturasbwg-7ju4
Nivel del mar mínimo7z6g-yx9q
Nivel del mar máximouxy3-jchf
Nivel del maria8x-22em
Presión Atmosferica62tk-nxj5
Precipitacións54a-sgyg

3.1 Precipitación (s54a-sgyg)

Vamos a consultar los datos de precipitación reportada en la página, por ende vamos a usar el código s54a-sgyg. Para esto usamos el método Socrata, pasamos la dirección del repositorio y None que corresponde a la no autenticación

# conexión cliente usando socrata al repositorio de datos abiertos
client = Socrata("www.datos.gov.co", None)
WARNING:root:Requests made without an app_token will be subject to strict throttling limits.

Una vez creado el cliente empezamos a hacer la consulta de datos usando client.get y pasando los respectivos parámetros dataset_identifier, de la tabla anterior , y limit para generar consultas no muy grandes para efectos demostrativos. El resultado es una lista con múltiples diccionarios como se puede ver a continuación.

# Solicitud de informacion al repositorio de interés
results = client.get(dataset_identifier="s54a-sgyg", limit=2000)
results[:1]
[{'codigoestacion': '0023195230', 'codigosensor': '0240', 'fechaobservacion': '2023-09-20T13:10:00.000', 'valorobservado': '0', 'nombreestacion': 'NEOMUNDO', 'departamento': 'SANTANDER', 'municipio': 'BUCARAMANGA', 'zonahidrografica': 'MEDIO MAGDALENA', 'latitud': '7.09999722', 'longitud': '-73.11', 'descripcionsensor': 'PRECIPITACIÓN', 'unidadmedida': 'mm'}]

Estos resultados los podemos convertir en un Dataframe usando pandas.Dataframe.from_records

results_df = pd.DataFrame.from_records(results)
results_df.head()
Loading...

Ahora podemos usar filtrar los datos por diferentes campos como el codigoestacion, fechaobservacion, o valorobservado. Podemos pasar parámetros SQL como where, AND, IN, entre otros, en el método client.get

# client.get?
# Solicitud de informacion para la estación de la Universidad Nacional - Bogotá - 0021205012
ppt_query = client.get(
    dataset_identifier="s54a-sgyg",
    select="fechaobservacion, valorobservado, codigoestacion",
    where="codigoestacion IN ('0021205012') \
                              AND fechaobservacion > '2017'",
)
df_est = pd.DataFrame.from_records(ppt_query)
df_est.head()
Loading...

Gráfico de la serie temporal

Podemos generar una serie temporal usando la información resultado de la consulta. Sin embargo, primero debemos revisar el tipo de dato de cada columna

df_est.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 3 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   fechaobservacion  1000 non-null   object
 1   valorobservado    1000 non-null   object
 2   codigoestacion    1000 non-null   object
dtypes: object(3)
memory usage: 23.6+ KB
df_est["fechaobservacion"] = pd.to_datetime(df_est["fechaobservacion"])
df_est.set_index("fechaobservacion", inplace=True)
df_est.valorobservado = df_est["valorobservado"].astype(float)
df_est = df_est.sort_index()
df_est.tail()
Loading...
# pd.options.plotting.backend = 'holoviews'
fig, ax = plt.subplots(figsize=(12, 3))
df_est["valorobservado"].plot(ax=ax, drawstyle="steps")
<Axes: xlabel='fechaobservacion'>
<Figure size 1200x300 with 1 Axes>

Podemos solicitar información para estaciones que reportan datos en el último mes

ppt_query = client.get(
    dataset_identifier="s54a-sgyg",
    select="fechaobservacion, valorobservado, codigoestacion, nombreestacion",
    where="fechaobservacion > '2023-09-11'",
)
df_ult = pd.DataFrame.from_records(ppt_query)
df_ult.head()
Loading...

3.2 Temperatura (sbwg-7ju4)

De manera similar podemos consultar otros registros como los de temperatura. Cambiamos el identificador de set de datos y generamos una nueva consulta

# Solicitud de informacion para la estación de la Universidad Nacional - Bogotá - 0021205012
temp_query = client.get(
    dataset_identifier="sbwg-7ju4",
    select="fechaobservacion, valorobservado, codigoestacion",
    where="codigoestacion IN ('0021205012') \
                              AND fechaobservacion > '2020'",
)
df_temp = pd.DataFrame.from_records(temp_query)
df_temp.index = pd.to_datetime(df_temp["fechaobservacion"])
df_temp.valorobservado = df_temp["valorobservado"].astype(float)
df_temp = df_temp.sort_index()
df_temp.tail()
---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connectionpool.py:534, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    533 try:
--> 534     response = conn.getresponse()
    535 except (BaseSSLError, OSError) as e:

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connection.py:565, in HTTPConnection.getresponse(self)
    564 # Get the response from http.client.HTTPConnection
--> 565 httplib_response = super().getresponse()
    567 try:

File ~/micromamba/envs/cdh-python/lib/python3.12/http/client.py:1430, in HTTPConnection.getresponse(self)
   1429 try:
-> 1430     response.begin()
   1431 except ConnectionError:

File ~/micromamba/envs/cdh-python/lib/python3.12/http/client.py:331, in HTTPResponse.begin(self)
    330 while True:
--> 331     version, status, reason = self._read_status()
    332     if status != CONTINUE:

File ~/micromamba/envs/cdh-python/lib/python3.12/http/client.py:292, in HTTPResponse._read_status(self)
    291 def _read_status(self):
--> 292     line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
    293     if len(line) > _MAXLINE:

File ~/micromamba/envs/cdh-python/lib/python3.12/socket.py:720, in SocketIO.readinto(self, b)
    719 try:
--> 720     return self._sock.recv_into(b)
    721 except timeout:

File ~/micromamba/envs/cdh-python/lib/python3.12/ssl.py:1251, in SSLSocket.recv_into(self, buffer, nbytes, flags)
   1248         raise ValueError(
   1249           "non-zero flags not allowed in calls to recv_into() on %s" %
   1250           self.__class__)
-> 1251     return self.read(nbytes, buffer)
   1252 else:

File ~/micromamba/envs/cdh-python/lib/python3.12/ssl.py:1103, in SSLSocket.read(self, len, buffer)
   1102 if buffer is not None:
-> 1103     return self._sslobj.read(len, buffer)
   1104 else:

TimeoutError: The read operation timed out

The above exception was the direct cause of the following exception:

ReadTimeoutError                          Traceback (most recent call last)
File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/requests/adapters.py:667, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    666 try:
--> 667     resp = conn.urlopen(
    668         method=request.method,
    669         url=url,
    670         body=request.body,
    671         headers=request.headers,
    672         redirect=False,
    673         assert_same_host=False,
    674         preload_content=False,
    675         decode_content=False,
    676         retries=self.max_retries,
    677         timeout=timeout,
    678         chunked=chunked,
    679     )
    681 except (ProtocolError, OSError) as err:

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connectionpool.py:841, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    839     new_e = ProtocolError("Connection aborted.", new_e)
--> 841 retries = retries.increment(
    842     method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    843 )
    844 retries.sleep()

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/util/retry.py:474, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    473 if read is False or method is None or not self._is_method_retryable(method):
--> 474     raise reraise(type(error), error, _stacktrace)
    475 elif read is not None:

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/util/util.py:39, in reraise(tp, value, tb)
     38         raise value.with_traceback(tb)
---> 39     raise value
     40 finally:

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connectionpool.py:787, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    786 # Make the request on the HTTPConnection object
--> 787 response = self._make_request(
    788     conn,
    789     method,
    790     url,
    791     timeout=timeout_obj,
    792     body=body,
    793     headers=headers,
    794     chunked=chunked,
    795     retries=retries,
    796     response_conn=response_conn,
    797     preload_content=preload_content,
    798     decode_content=decode_content,
    799     **response_kw,
    800 )
    802 # Everything went great!

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connectionpool.py:536, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    535 except (BaseSSLError, OSError) as e:
--> 536     self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
    537     raise

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/urllib3/connectionpool.py:367, in HTTPConnectionPool._raise_timeout(self, err, url, timeout_value)
    366 if isinstance(err, SocketTimeout):
--> 367     raise ReadTimeoutError(
    368         self, url, f"Read timed out. (read timeout={timeout_value})"
    369     ) from err
    371 # See the above comment about EAGAIN in Python 3.

ReadTimeoutError: HTTPSConnectionPool(host='www.datos.gov.co', port=443): Read timed out. (read timeout=10)

During handling of the above exception, another exception occurred:

ReadTimeout                               Traceback (most recent call last)
Cell In[26], line 2
      1 # Solicitud de informacion para la estación de la Universidad Nacional - Bogotá - 0021205012
----> 2 temp_query = client.get(
      3     dataset_identifier="sbwg-7ju4",
      4     select="fechaobservacion, valorobservado, codigoestacion",
      5     where="codigoestacion IN ('0021205012') \
      6                               AND fechaobservacion > '2020'",
      7 )
      8 df_temp = pd.DataFrame.from_records(temp_query)
      9 df_temp.index = pd.to_datetime(df_temp["fechaobservacion"])

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/sodapy/socrata.py:412, in Socrata.get(self, dataset_identifier, content_type, **kwargs)
    409 params.update(kwargs)
    410 params = utils.clear_empty_values(params)
--> 412 response = self._perform_request(
    413     "get", resource, headers=headers, params=params
    414 )
    415 return response

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/sodapy/socrata.py:551, in Socrata._perform_request(self, request_type, resource, **kwargs)
    548 # set a timeout, just to be safe
    549 kwargs["timeout"] = self.timeout
--> 551 response = getattr(self.session, request_type)(uri, **kwargs)
    553 # handle errors
    554 if response.status_code not in (200, 202):

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/requests/sessions.py:602, in Session.get(self, url, **kwargs)
    594 r"""Sends a GET request. Returns :class:`Response` object.
    595 
    596 :param url: URL for the new :class:`Request` object.
    597 :param \*\*kwargs: Optional arguments that ``request`` takes.
    598 :rtype: requests.Response
    599 """
    601 kwargs.setdefault("allow_redirects", True)
--> 602 return self.request("GET", url, **kwargs)

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/requests/sessions.py:589, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    584 send_kwargs = {
    585     "timeout": timeout,
    586     "allow_redirects": allow_redirects,
    587 }
    588 send_kwargs.update(settings)
--> 589 resp = self.send(prep, **send_kwargs)
    591 return resp

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/requests/sessions.py:703, in Session.send(self, request, **kwargs)
    700 start = preferred_clock()
    702 # Send the request
--> 703 r = adapter.send(request, **kwargs)
    705 # Total elapsed time of the request (approximately)
    706 elapsed = preferred_clock() - start

File ~/micromamba/envs/cdh-python/lib/python3.12/site-packages/requests/adapters.py:713, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    711     raise SSLError(e, request=request)
    712 elif isinstance(e, ReadTimeoutError):
--> 713     raise ReadTimeout(e, request=request)
    714 elif isinstance(e, _InvalidHeader):
    715     raise InvalidHeader(e, request=request)

ReadTimeout: HTTPSConnectionPool(host='www.datos.gov.co', port=443): Read timed out. (read timeout=10)
fig, ax = plt.subplots(figsize=(12, 3))
df_temp["valorobservado"].plot(c="C00", lw=0.5, ax=ax)

4. Datos en tiempo “Causi-real” de IDEAM

De igual manera, el IDEAM dispone de una tabla de datos en tiempo cercano a la medición. Esta tabla corresponde al dataset_identifier="57sv-p2fu". Generemos una consulta básica para ver los campos contenidos dentro de esta tabla en el último día

time_now = datetime.now()
time = time_now - timedelta(days=10)
time

Convertimos la fecha en un str para incluirlo en la consulta

time_str = f"{to_datetime(time):%Y-%m-%d}"
time_str
nrt_query = client.get(
    dataset_identifier="57sv-p2fu",
    select="*",
    where="fechaobservacion >= '{}'".format(time_str),
    limit=2000,
)
df_nrt = pd.DataFrame.from_records(nrt_query)
df_nrt.head()

Los primeros registros nos indican que hay mediciones cercanas a las fechas de la ejecución de este cuadernillo. Generemos una consulta más específica para la estacion 0024035340 correspondiente al Aeropuerto Alberto Lleras Camargo de Sogamoso.

cod_est = "0024035340"
aero_query = client.get(
    dataset_identifier="57sv-p2fu",
    select="*",
    where="fechaobservacion >= '{}'\
                        AND codigoestacion IN ('{}')".format(
        time_str, cod_est
    ),
    limit=2000,
)
df_aero = pd.DataFrame.from_records(aero_query)
df_aero.head(10)

Para validar los sensores que tiene esta estacion podemo usar el método .unique() de Pandas

df_aero["codigosensor"].unique()

Podemos centrar aún mas la consulta agregándole el sensor de temperatura codigosensor=0071

cod_sensor = "0071"
aero_query = client.get(
    dataset_identifier="57sv-p2fu",
    select="fechaobservacion, valorobservado",
    where="fechaobservacion >= '{}'\
                        AND codigoestacion IN ('{}') \
                        AND codigosensor IN ('{}')".format(
        time_str, cod_est, cod_sensor
    ),
    limit=2000,
)
df_aero = pd.DataFrame.from_records(aero_query)
df_aero

Ahora generemos un gráfico rápido de la serie de temperatura para las últimas 24 horas

fig, ax = plt.subplots(figsize=(10, 3))
df_aero.index = pd.to_datetime(df_aero["fechaobservacion"])
df_aero.valorobservado = df_aero["valorobservado"].astype(float)
df_aero.plot(ax=ax)
ax.xaxis.set_major_locator(HourLocator(interval=4))  # tick every four hours
ax.xaxis.set_major_formatter(DateFormatter("%y-%m-%d\n%H:%M"))

Conclusiones

En este cuadernillo aprendimos una manera fácil y rápida como acceder a la información histórica y presente de las estaciones hidrometeorológicas del IDEAM. De igual modo aprendimos a visualizar las estaciones usando mapas interactivos. También aprendimos a generar consultas a diferentes grupos de datos usando sintaxis SQL y el aplicativo socrata de la plataforma de datos abiertos del gobierno Colombiano.

Resources and references

  • Rose, B. E. J., Kent, J., Tyle, K., Clyne, J., Banihirwe, A., Camron, D., May, R., Grover, M., Ford, R. R., Paul, K., Morley, J., Eroglu, O., Kailyn, L., & Zacharias, A. (2023). Pythia Foundations (Version v2023.05.01) Rose et al. (2023)
References
  1. Rose, B., Kent, J., Tyle, K., Clyne, Banihirwe, A., Camron, D., Ford, R., Morley, J., Grover, M., Eroglu, O., Paul, K., May, R., Lkailynncar, Irving, D., Uieda, L., Ojaybee, Blain, P., & Moon, Z. (2023). ProjectPythia/pythia-foundations: v2023.05.01. Zenodo. 10.5281/ZENODO.7884572