Distribución de la palma de cera (Ceroxylon quindiuense) en Colombia¶
Librerías y funciones¶
In [ ]:
# Instalación
!pip install rasterio --quiet
!pip install pygbif --quiet
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 22.2/22.2 MB 79.0 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 70.2/70.2 kB 4.6 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.4/61.4 kB 5.4 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 66.4/66.4 kB 5.7 MB/s eta 0:00:00
In [ ]:
import pandas as pd
import pygbif
import geopandas as gpd
import rasterio
import rasterio.plot
import numpy as np
import matplotlib.pyplot as plt
import folium
import plotly.express as px
In [ ]:
# Biblioteca requerida para mapas interactivos
!pip install mapclassify --quiet
import mapclassify
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/59.1 kB ? eta -:--:-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 59.1/59.1 kB 3.1 MB/s eta 0:00:00
In [ ]:
def consulta_especie(especie):
limite = 300 # Límite de registros por solicitud
offset = 0 # Desplazamiento para iniciar la solicitud
registros_acumulados = [] # Lista para acumular los resultados
# Ciclo que obtiene los registros en la cantidad especificada
# en la variable limite
while True:
# Solicitud
res = pygbif.occurrences.search(
scientificName=especie,
hasCoordinate=True,
hasGeospatialIssue=False,
limit=limite,
offset=offset
)
# Extraer resultados
registros = res.get("results", [])
# Si ya no hay resultados, se detiene el ciclo
if not registros:
break
# Agregar registros nuevos al acumulado
registros_acumulados.extend(registros)
offset += limite
print(len(pd.DataFrame(registros_acumulados)))
return pd.DataFrame(registros_acumulados)
Datos de presencia de la palma de cera¶
In [ ]:
#Datos espaciales
paises_gdf = gpd.read_file('https://raw.githubusercontent.com/datos-geoespaciales-biodiversidad/python/refs/heads/main/datos/otros/naturalearth/paises.gpkg')
dptos_col = gpd.read_file('https://github.com/monialvarez/files/blob/main/dptos_colombia.gpkg?raw=true')
/usr/local/lib/python3.11/dist-packages/pyogrio/raw.py:198: RuntimeWarning: File /vsicurl/https://github.com/monialvarez/files/blob/main/dptos_colombia.gpkg?raw=true has GPKG application_id, but non conformant file extension return ogr_read(
In [ ]:
palma_df = consulta_especie('Ceroxylon quindiuense')
6524
In [ ]:
print(list(palma_df.columns))
palma_df = palma_df[['species', 'dateIdentified', 'decimalLongitude', 'decimalLatitude', 'countryCode']]
palma_df.head()
['key', 'datasetKey', 'publishingOrgKey', 'installationKey', 'hostingOrganizationKey', 'publishingCountry', 'protocol', 'lastCrawled', 'lastParsed', 'crawlId', 'extensions', 'basisOfRecord', 'occurrenceStatus', 'taxonKey', 'kingdomKey', 'phylumKey', 'classKey', 'orderKey', 'familyKey', 'genusKey', 'speciesKey', 'acceptedTaxonKey', 'scientificName', 'acceptedScientificName', 'kingdom', 'phylum', 'order', 'family', 'genus', 'species', 'genericName', 'specificEpithet', 'taxonRank', 'taxonomicStatus', 'iucnRedListCategory', 'dateIdentified', 'decimalLatitude', 'decimalLongitude', 'coordinateUncertaintyInMeters', 'continent', 'stateProvince', 'gadm', 'year', 'month', 'day', 'eventDate', 'startDayOfYear', 'endDayOfYear', 'issues', 'modified', 'lastInterpreted', 'references', 'license', 'isSequenced', 'identifiers', 'media', 'facts', 'relations', 'isInCluster', 'datasetName', 'recordedBy', 'identifiedBy', 'geodeticDatum', 'class', 'countryCode', 'recordedByIDs', 'identifiedByIDs', 'gbifRegion', 'country', 'publishedByGbifRegion', 'rightsHolder', 'identifier', 'http://unknown.org/nick', 'informationWithheld', 'verbatimEventDate', 'gbifID', 'verbatimLocality', 'collectionCode', 'occurrenceID', 'taxonID', 'catalogNumber', 'institutionCode', 'eventTime', 'http://unknown.org/captive', 'identificationID', 'occurrenceRemarks', 'reproductiveCondition', 'identificationRemarks', 'individualCount', 'acceptedNameUsage', 'institutionID', 'county', 'locality', 'verbatimCoordinateSystem', 'municipality', 'language', 'type', 'verbatimIdentification', 'vernacularName', 'projectId', 'elevation', 'elevationAccuracy', 'sex', 'georeferencedBy', 'datasetID', 'samplingProtocol', 'recordNumber', 'eventID', 'habitat', 'verbatimSRS', 'locationRemarks', 'locationID', 'verbatimElevation', 'establishmentMeans', 'coordinatePrecision', 'samplingEffort', 'eventRemarks', 'fieldNumber', 'taxonRemarks', 'locationAccordingTo', 'georeferencedDate', 'nomenclaturalCode', 'ownerInstitutionCode', 'collectionID', 'lifeStage', 'organismQuantity', 'organismQuantityType', 'georeferenceProtocol', 'organismID', 'georeferenceRemarks', 'associatedSequences', 'taxonConceptID', 'dynamicProperties', 'parentEventID', 'institutionKey', 'collectionKey', 'georeferenceVerificationStatus', 'previousIdentifications', 'higherClassification', 'fieldNotes', 'accessRights', 'verbatimTaxonRank', 'georeferenceSources', 'organismRemarks', 'sampleSizeUnit', 'sampleSizeValue', 'preparations', 'higherGeography', 'bibliographicCitation', 'otherCatalogNumbers', 'higherGeographyID', 'disposition', 'networkKeys', 'nomenclaturalStatus', 'waterBody', 'namePublishedIn', 'depth', 'depthAccuracy', 'geologicalContextID', 'typifiedName']
Out[ ]:
species | dateIdentified | decimalLongitude | decimalLatitude | countryCode | |
---|---|---|---|---|---|
0 | Ceroxylon quindiuense | 2025-01-27T17:44:33 | -75.465477 | 4.624254 | CO |
1 | Ceroxylon quindiuense | 2025-01-30T18:21:45 | -75.560286 | 4.691131 | CO |
2 | Ceroxylon quindiuense | 2025-02-02T16:13:48 | -75.411530 | 4.658287 | CO |
3 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.517884 | 4.746321 | CO |
4 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.497903 | 4.738804 | CO |
In [ ]:
geom = gpd.points_from_xy(palma_df.decimalLongitude, palma_df.decimalLatitude)
palma_gdf = gpd.GeoDataFrame(palma_df, geometry=geom)
palma_gdf.head()
Out[ ]:
species | dateIdentified | decimalLongitude | decimalLatitude | countryCode | geometry | |
---|---|---|---|---|---|---|
0 | Ceroxylon quindiuense | 2025-01-27T17:44:33 | -75.465477 | 4.624254 | CO | POINT (-75.46548 4.62425) |
1 | Ceroxylon quindiuense | 2025-01-30T18:21:45 | -75.560286 | 4.691131 | CO | POINT (-75.56029 4.69113) |
2 | Ceroxylon quindiuense | 2025-02-02T16:13:48 | -75.411530 | 4.658287 | CO | POINT (-75.41153 4.65829) |
3 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.517884 | 4.746321 | CO | POINT (-75.51788 4.74632) |
4 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.497903 | 4.738804 | CO | POINT (-75.4979 4.7388) |
In [ ]:
#palma_gdf.explore()
Distribución general de los datos¶
In [ ]:
fig, ax = plt.subplots(figsize=(8, 6))
paises_gdf[(paises_gdf['CONTINENT'] == 'South America') | (paises_gdf['CONTINENT'] == 'North America')].plot(
ax=ax,
color="white",
edgecolor="black"
)
palma_gdf.plot(
ax=ax,
marker="o",
color="blue",
#edgecolor='blue',
linewidth=1,
markersize=5
)
# Limitar el rango de los ejes
ax.set_xlim(-85.0, -65.0)
ax.set_ylim(-10.0, 15)
plt.show()
Distribución en Colombia¶
In [ ]:
palma_co = palma_gdf.sjoin(dptos_col, predicate='intersects')
palma_co.head()
/usr/local/lib/python3.11/dist-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries. Use `to_crs()` to reproject one of the input geometries to match the CRS of the other. Left CRS: None Right CRS: EPSG:4326 return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs) # noqa: B026
Out[ ]:
species | dateIdentified | decimalLongitude | decimalLatitude | countryCode | geometry | index_right | OBJECTID | DeCodigo | DeNombre | DeArea | DeNorma | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Ceroxylon quindiuense | 2025-01-27T17:44:33 | -75.465477 | 4.624254 | CO | POINT (-75.46548 4.62425) | 6 | 7 | 63 | Quindío | 1932.978812 | Ley No. 2 de 1966 |
1 | Ceroxylon quindiuense | 2025-01-30T18:21:45 | -75.560286 | 4.691131 | CO | POINT (-75.56029 4.69113) | 6 | 7 | 63 | Quindío | 1932.978812 | Ley No. 2 de 1966 |
2 | Ceroxylon quindiuense | 2025-02-02T16:13:48 | -75.411530 | 4.658287 | CO | POINT (-75.41153 4.65829) | 9 | 10 | 73 | Tolima | 24128.130426 | Constitución Política de Colombia 1886 |
3 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.517884 | 4.746321 | CO | POINT (-75.51788 4.74632) | 7 | 8 | 66 | Risaralda | 3556.507527 | Ley No. 70 de 1966 |
4 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.497903 | 4.738804 | CO | POINT (-75.4979 4.7388) | 7 | 8 | 66 | Risaralda | 3556.507527 | Ley No. 70 de 1966 |
In [ ]:
palma_dptos = palma_co.groupby('DeNombre').count()[['species']].sort_values(by = 'species', ascending=False)
palma_co.groupby('DeNombre').count()[['species']].sort_values(by = 'species', ascending=False)
Out[ ]:
species | |
---|---|
DeNombre | |
Tolima | 4224 |
Meta | 1591 |
Valle del Cauca | 297 |
Quindío | 94 |
Santander | 59 |
Risaralda | 57 |
Antioquia | 57 |
Cundinamarca | 53 |
Caldas | 43 |
Boyacá | 14 |
Huila | 10 |
Putumayo | 6 |
Nariño | 3 |
Cauca | 2 |
Caquetá | 1 |
Magdalena | 1 |
Norte de Santander | 1 |
In [ ]:
fig = px.bar(palma_dptos, title='Cantidad de datos de presencia de Palma de cera por departamento')
# Personalización
fig.update_layout(
xaxis_title='Municipio',
yaxis_title='Cantidad de registros',
width=800, # Ancho de la figura
height=600 # Alto de la figura
)
In [ ]:
fig, ax = plt.subplots(figsize=(8, 6))
dptos_col.plot(
ax=ax,
color="white",
edgecolor="black"
)
palma_gdf[palma_gdf.countryCode=='CO'].plot(
ax=ax,
marker="o",
color="blue",
#edgecolor='blue',
linewidth=1,
markersize=5
)
Out[ ]:
<Axes: >
In [ ]:
palma_gdf
Out[ ]:
species | dateIdentified | decimalLongitude | decimalLatitude | countryCode | geometry | |
---|---|---|---|---|---|---|
0 | Ceroxylon quindiuense | 2025-01-27T17:44:33 | -75.465477 | 4.624254 | CO | POINT (-75.46548 4.62425) |
1 | Ceroxylon quindiuense | 2025-01-30T18:21:45 | -75.560286 | 4.691131 | CO | POINT (-75.56029 4.69113) |
2 | Ceroxylon quindiuense | 2025-02-02T16:13:48 | -75.411530 | 4.658287 | CO | POINT (-75.41153 4.65829) |
3 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.517884 | 4.746321 | CO | POINT (-75.51788 4.74632) |
4 | Ceroxylon quindiuense | 2025-02-02T16:13:49 | -75.497903 | 4.738804 | CO | POINT (-75.4979 4.7388) |
... | ... | ... | ... | ... | ... | ... |
6519 | Ceroxylon quindiuense | NaN | -76.628480 | 3.441610 | CO | POINT (-76.62848 3.44161) |
6520 | Ceroxylon quindiuense | NaN | -75.489538 | 4.462424 | CO | POINT (-75.48954 4.46242) |
6521 | Ceroxylon quindiuense | NaN | -75.487610 | 4.462444 | CO | POINT (-75.48761 4.46244) |
6522 | Ceroxylon quindiuense | NaN | -75.491878 | 4.456904 | CO | POINT (-75.49188 4.4569) |
6523 | Ceroxylon quindiuense | NaN | -75.485556 | 4.118056 | CO | POINT (-75.48556 4.11806) |
6524 rows × 6 columns
Condiciones climáticas¶
In [ ]:
temperatura_media_anual = rasterio.open(
'https://github.com/datos-geoespaciales-biodiversidad/python/raw/refs/heads/main/datos/clima/worldclim/2.1-10m-bio/wc2.1_10m_bio_1.tif'
)
In [ ]:
fig, ax = plt.subplots(figsize=(8, 8))
paises_gdf[(paises_gdf['CONTINENT'] == 'South America') | (paises_gdf['CONTINENT'] == 'North America')].plot(
ax=ax,
color="white",
edgecolor="black",
)
rasterio.plot.show(
temperatura_media_anual,
cmap="coolwarm", # colores
ax=ax,
title="Temperatura media anual",
zorder=1
)
palma_gdf.plot(
ax=ax,
marker="o",
color="blue",
#edgecolor='blue',
linewidth=1,
markersize=3
)
# Limitar el rango de los ejes
ax.set_xlim(-85.0, -65.0)
ax.set_ylim(-10.0, 15)
plt.show()
/usr/local/lib/python3.11/dist-packages/matplotlib/colors.py:777: RuntimeWarning: overflow encountered in multiply xa *= self.N