Análisis Exploratorio de Incendios Forestales Usando Datos de Focos de Calor del Sensor MODIS¶

Observatorio Provincial de Gestión de Riesgos - Secretaría de Emergencias y Gestión de Riesgos - Gobierno de la provincia de Neuquén

¿CUÁL ES LA FUNCIÓN DEL OBSERVATORIO PROVINCIAL DE GESTIÓN DE RIESGOS?¶

El Observatorio Provincial de Gestión de Riesgos tiene como objetivo contribuir al diseño, implementación y monitoreo de políticas públicas tendientes a optimizar la gestión integral del riesgo en la provincia del Neuquén, a través del desarrollo de un sistema de información que permita recopilar, analizar y consolidar datos relevantes para la toma de decisiones y la mejora continua de las estrategias de reducción de riesgo y abordaje de situaciones de emergencias. Sus funciones se enmarcan en la ley provincial 2713: “Enfoque de riesgo en políticas de planificación y desarrollo territorial de la Provincia del Neuquén”.

FUENTES DE INFORMACIÓN:

CIAT – Centro de Información de Alerta Temprana

SIGISVI - Sistema Integral de Gestión de la Información de Seguridad Vial

Vialidad Provincial (Estado de las rutas)

RAPH (SIEN) Registro de Atención Pre Hospitalaria

Medios gráficos de comunicación

OpenWeatherMap

Servicio meteorológico Nacional

Policía de la provincia de Neuquén

Dirección Bomberos de la Policía

Sistema de Manejo del Fuego

FICHA TÉCNICA¶

Período de Análisis: Noviembre de 2000 a Mayo de 2024

Cantidad de Registros: 5,596 focos de calor detectados

Fuentes de Datos:

Focos de Calor: University of Maryland. (n.d.). Fire Information for Resource Management System (FIRMS). NASA. Recuperado de https://firms.modaps.eosdis.nasa.gov/

Modelos Digitales de Elevación (MDE): Instituto Geográfico Nacional (IGN). (2019). Nuevo Modelo Digital de Elevaciones de la República Argentina. Recuperado de https://www.ign.gob.ar/content/nuevo-modelo-digital-de-elevaciones-para-la-rep%C3%BAblica-argentina

Vegetación: Movia, C. (1982). Mapa de Vegetación de la República Argentina. Instituto Nacional de Tecnología Agropecuaria (INTA) Y Centro de Investigación y Extensión Forestal Andino Patagónico (CIEFAP). Cartografía de 

Centros Urbanos y Redes Viales: OpenStreetMap. (n.d.). Datos Geoespaciales Abiertos. Recuperado de https://www.openstreetmap.org/ Y Consejo de Planificación y Acción para el Desarrollo (COPADE). 


Este trabajo tiene como objetivo realizar un análisis estadístico descriptivo que sirva como base para la toma de decisiones estratégicas en el marco del "Operativo Fuego" de la Provincia del Neuquén. Este operativo se estructura en torno a tres pilares fundamentales: comunicación preventiva, coordinación interinstitucional y articulación con gobiernos locales, con el propósito de prevenir, mitigar y responder de manera eficiente a los incendios forestales. Los datos generados a partir de este análisis tienen como finalidad priorizar áreas de riesgo, optimizar la asignación de recursos y diseñar estrategias específicas de respuesta ante emergencias. Además, permiten mejorar las campañas de comunicación preventiva, coordinar esfuerzos entre instituciones y apoyar la planificación local con información técnica y geoespacial precisa.

El análisis se basa en datos recopilados por el sensor MODIS (Moderate Resolution Imaging Spectroradiometer), instalado en los satélites Terra y Aqua de la NASA. Este sensor detecta focos de calor en tiempo real, proporcionando información crítica sobre áreas con temperaturas significativamente más altas que su entorno. Estas anomalías térmicas pueden estar asociadas a incendios forestales, quemas de biomasa o actividades industriales. La información obtenida a través de MODIS permite identificar patrones temporales y espaciales de los focos de calor, lo que es esencial para comprender su dinámica y distribución. Para evitar confusiones con infocos de calor derivados de actividades propias de la industria hidrocarburífera, se aplicó una máscara que excluye zonas petroleras, asegurando así un análisis más preciso de los focos de calor relacionados con incendios forestales y de interfase. Para maximizar la utilidad de estos datos, el análisis se complementa con el cruce de variables clave como:

  • Vegetación
  • Relieve
  • Pendientes
  • Alturas
  • Proximidad a Centros Urbanos y Redes Viales

LIBRERÍAS¶

In [1]:
# Instalar Librerías

#%pip install pandas matplotlib seaborn geopandas folium plotly nltk scipy wordcloud nbconvert
In [2]:
# Importar de Librerías

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import geopandas as gpd
import folium
import plotly.express as px
import nltk


from scipy.interpolate import make_interp_spline
from scipy.interpolate import make_interp_spline
from nltk.corpus import stopwords
from wordcloud import WordCloud, STOPWORDS
from wordcloud import WordCloud
from nltk.corpus import stopwords
from folium.plugins import MarkerCluster
from folium.plugins import HeatMap, MeasureControl, MarkerCluster

DATAFRAME Y VISUALIZACIÓN DE ARCHIVOS¶

In [3]:
# Lectura Archivo

df_incendios = pd.read_csv('modis_incendios.csv')

pd.set_option('display.max_rows', None)

df_incendios.head()
Out[3]:
fid LATITUDE LONGITUDE BRIGHTNESS SCAN TRACK ACQ_DATE ACQ_TIME SATELLITE INSTRUMENT ... DAYNIGHT TYPE dem_nqn_re comun_veg dist_aurb dist_rut nombre region Aspecto dem_nqn_pe
0 5 -38.3537 -70.2693 319.9 1.0 1.0 2000/11/19 1459 Terra MODIS ... D 0.0 1157.56909 E18:: Colliguaya integerrima,Trevoa patagonica... NaN NaN Picunches Centro Oeste 12.78170 14.38076
1 11 -38.6914 -70.1088 328.8 2.2 1.4 2000/12/08 1529 Terra MODIS ... D 0.0 1019.21796 E10: Larrea divaricata y Atriplex lampa, con H... NaN NaN Picunches Centro Oeste 117.08196 9.02464
2 12 -38.6882 -70.1160 336.0 2.2 1.4 2000/12/08 1529 Terra MODIS ... D 0.0 1108.71448 E16: Colliguaya integerrima, Verbena glauca y ... NaN NaN Picunches Centro Oeste 85.72124 4.19148
3 13 -37.8495 -70.3602 325.5 1.6 1.3 2000/12/09 1434 Terra MODIS ... D 0.0 1364.26404 E18:: Colliguaya integerrima,Trevoa patagonica... NaN NaN Loncopué Norte 38.99630 20.01369
4 14 -37.8530 -70.3427 325.8 1.6 1.3 2000/12/09 1434 Terra MODIS ... D 0.0 1266.30603 E18:: Colliguaya integerrima,Trevoa patagonica... NaN NaN Loncopué Norte 176.16109 7.55501

5 rows × 24 columns

VALORES¶

In [4]:
# Reemplazo de valores nulos por NA
# Lista de valores considerados como nulos o vacíos
valores_nulos = ['NaN', 'null', 'S/D', '', ' ', 'N/A', 'None', None]

# Reemplazar todos los valores especificados en 'valores_nulos' por np.nan
df_incendios.replace(valores_nulos, np.nan, inplace=True)

# Verificar si hay cambios mostrando, por ejemplo, la suma de valores nulos por columna
print(df_incendios.isna().sum())
fid              0
LATITUDE         0
LONGITUDE        0
BRIGHTNESS       0
SCAN             0
TRACK            0
ACQ_DATE         0
ACQ_TIME         0
SATELLITE        0
INSTRUMENT       0
CONFIDENCE       0
VERSION          0
BRIGHT_T31       0
FRP              0
DAYNIGHT         0
TYPE             0
dem_nqn_re       2
comun_veg        0
dist_aurb     5489
dist_rut      3875
nombre           0
region           0
Aspecto          5
dem_nqn_pe       0
dtype: int64

GRÁFICOS¶

ANÁLISIS TEMPORAL¶

In [5]:
# Convertir la columna ACQ_DATE de df_incendios a formato datetime y crear df_date
df_incendios['ACQ_DATE'] = pd.to_datetime(df_incendios['ACQ_DATE'], errors='coerce')

# Crear un nuevo DataFrame df_date basado en df_incendios
df_date = df_incendios.copy()

FOCOS DE CALOR POR AÑO¶

In [6]:
# Extraer el año de la columna ACQ_DATE
df_date['year'] = df_date['ACQ_DATE'].dt.year



# Contar los casos por año
cases_per_year = df_date['year'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_year.plot(kind='bar', color='skyblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Año (2000-2024)', fontsize=16)
plt.xlabel('Año', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_year.max() * 1.2)  # Aumentar un 10% el límite superior del eje Y

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_year):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image
In [7]:
# Filtrar los casos de incendios para los años 2023 y 2024
df_filtered = df_date[(df_date['year'] == 2023) | (df_date['year'] == 2024)]

# Contar los casos por año en el DataFrame filtrado
cases_per_year = df_filtered['year'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_year.plot(kind='bar', color='skyblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Año (2023 y 2024)', fontsize=16)
plt.xlabel('Año', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_year.max() * 1.2)  # Aumentar un 20% el límite superior del eje Y

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_year):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR MES¶

In [8]:
# Extraer el mes de la columna ACQ_DATE
df_date['month'] = df_date['ACQ_DATE'].dt.month

# Contar los casos por mes
cases_per_month = df_date['month'].value_counts().sort_index()

# Diccionario para mapear los números de los meses a sus nombres
meses = {1: 'Enero', 2: 'Febrero', 3: 'Marzo', 4: 'Abril', 5: 'Mayo', 6: 'Junio', 
         7: 'Julio', 8: 'Agosto', 9: 'Septiembre', 10: 'Octubre', 11: 'Noviembre', 12: 'Diciembre'}

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_month.plot(kind='bar', color='skyblue')

# Reemplazar los números del eje X con los nombres de los meses
plt.xticks(ticks=range(len(cases_per_month)), labels=[meses[m] for m in cases_per_month.index])

# Agregar etiquetas y título
plt.title('Número de Casos por Mes', fontsize=16)
plt.xlabel('Mes', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_month.max() * 1.2)

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_month):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR DÍA DE LA SEMANA¶

In [9]:
# Extraer el día de la semana de la columna ACQ_DATE (0=Lunes, 6=Domingo)
df_date['weekday'] = df_date['ACQ_DATE'].dt.weekday

# Diccionario para mapear los números de los días de la semana a sus nombres
dias_semana = {0: 'Lunes', 1: 'Martes', 2: 'Miércoles', 3: 'Jueves', 4: 'Viernes', 5: 'Sábado', 6: 'Domingo'}

# Contar los casos por día de la semana
cases_per_weekday = df_date['weekday'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_weekday.plot(kind='bar', color='skyblue')

# Reemplazar los números del eje X con los nombres de los días de la semana
plt.xticks(ticks=range(len(cases_per_weekday)), labels=[dias_semana[d] for d in cases_per_weekday.index])

# Agregar etiquetas y título
plt.title('Número de Casos por Día de la Semana', fontsize=16)
plt.xlabel('Día de la Semana', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_weekday.max() * 1.2)

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_weekday):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

CRUCES DE VARIABLES TEMPORALES¶

In [10]:
# Crear una tabla cruzada (crosstab) entre el día de la semana y el mes
heatmap_data = pd.crosstab(df_date['month'], df_date['weekday'])

# Mapeo de los días de la semana y meses para las etiquetas
dias_semana = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo']
meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']

# Crear el mapa de calor sin etiquetas en las celdas y con una gama de colores "Reds"
plt.figure(figsize=(12, 8))
sns.heatmap(heatmap_data, annot=False, fmt='d', cmap='Reds', xticklabels=dias_semana, yticklabels=meses)

# Rotar las etiquetas del eje X y ajustar las del eje Y
plt.xticks(rotation=45, ha='right', fontsize=12)
plt.yticks(rotation=0, fontsize=12)

# Título y etiquetas
plt.title('Mapa de Calor: Número de Casos por Día de la Semana y Mes', fontsize=16)
plt.xlabel('Día de la Semana', fontsize=14)
plt.ylabel('Mes', fontsize=14)

# Mostrar el mapa de calor
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR DEPARTAMENTO¶

In [11]:
# Contar los casos por año
cases_per_year = df_date['nombre'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_year.plot(kind='bar', color='skyblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Departamento', fontsize=16)
plt.xlabel('Departamento', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_year.max() * 1.2)  # Aumentar un 10% el límite superior del eje Y

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_year):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image
In [12]:
# Crear una tabla cruzada (crosstab) entre el departamento ('nombre') y el mes
heatmap_data_dep_mes = pd.crosstab(df_date['nombre'], df_date['month'])

# Mapeo de los meses para las etiquetas
meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']

# Crear el mapa de calor
plt.figure(figsize=(15, 10))
sns.heatmap(heatmap_data_dep_mes, annot=False, fmt='d', cmap='Reds', xticklabels=meses, yticklabels=heatmap_data_dep_mes.index)

# Rotar las etiquetas del eje X para que no se superpongan
plt.xticks(rotation=45, ha='right', fontsize=10)
plt.yticks(fontsize=10)

# Título y etiquetas
plt.title('Mapa de Calor: Número de Casos por Departamento y Mes', fontsize=16)
plt.xlabel('Mes', fontsize=14)
plt.ylabel('Departamento', fontsize=14)

# Mostrar el mapa de calor
plt.tight_layout()
plt.show()
No description has been provided for this image
In [13]:
# Crear una tabla cruzada (crosstab) entre el departamento ('nombre') y el día de la semana ('weekday')
heatmap_data_dep_weekday = pd.crosstab(df_date['nombre'], df_date['weekday'])

# Mapeo de los días de la semana para las etiquetas
dias_semana = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo']

# Crear el mapa de calor
plt.figure(figsize=(15, 10))
sns.heatmap(heatmap_data_dep_weekday, annot=False, fmt='d', cmap='Reds', xticklabels=dias_semana, yticklabels=heatmap_data_dep_weekday.index)

# Rotar las etiquetas del eje X para que no se superpongan
plt.xticks(rotation=45, ha='right', fontsize=10)
plt.yticks(fontsize=10)

# Título y etiquetas
plt.title('Mapa de Calor: Número de Casos por Departamento y Día de la Semana', fontsize=16)
plt.xlabel('Día de la Semana', fontsize=14)
plt.ylabel('Departamento', fontsize=14)

# Mostrar el mapa de calor
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR REGIÓN¶

In [14]:
# Contar los casos por año
cases_per_year = df_date['region'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
cases_per_year.plot(kind='bar', color='skyblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Región', fontsize=16)
plt.xlabel('Región', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_year.max() * 1.2)  # Aumentar un 10% el límite superior del eje Y

# Agregar etiquetas de los valores en las barras
for i, value in enumerate(cases_per_year):
    plt.text(i, value + 1, str(value), ha='center', va='bottom')

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR Y ALTURA¶

In [15]:
# Crear el gráfico de dispersión
plt.figure(figsize=(10, 6))
plt.scatter(df_date['ACQ_DATE'], df_date['dem_nqn_re'], color='blue', alpha=0.5)

# Agregar etiquetas y título
plt.title('Gráfico de Dispersión de Alturas Por Año', fontsize=16)
plt.xlabel('Año', fontsize=14)
plt.ylabel('Altura', fontsize=14)

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR Y PENDIENTE¶

In [16]:
# Crear el gráfico de dispersión
plt.figure(figsize=(10, 6))
plt.scatter(df_date['ACQ_DATE'], df_date['dem_nqn_pe'], color='blue', alpha=0.5)

# Agregar etiquetas y título
plt.title('Gráfico de Dispersión de Pendientes', fontsize=16)
plt.xlabel('Fecha', fontsize=14)
plt.ylabel('Pendiente', fontsize=14)

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR Y ORIENTACIÓN DE LA PENDIENTE¶

In [17]:
# Crear una nueva columna que agrupa los valores de 'Aspecto' según las categorías definidas
def categorizar_aspecto(valor):
    if 0 <= valor <= 45 or 315 <= valor <= 360:
        return 'Ladera Norte'
    elif 45 < valor <= 135:
        return 'Ladera Este'
    elif 135 < valor <= 225:
        return 'Ladera Sur'
    elif 225 < valor <= 315:
        return 'Ladera Oeste'

# Aplicar la función para categorizar los valores de 'Aspecto'
df_date['ladera'] = df_date['Aspecto'].apply(categorizar_aspecto)

# Contar el número de casos por categoría de ladera
cases_per_ladera = df_date['ladera'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
bars = cases_per_ladera.plot(kind='bar', color='lightblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Ladera', fontsize=16)
plt.xlabel('Ladera', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Agregar etiquetas a las barras
for bar in bars.patches:
    plt.text(bar.get_x() + bar.get_width() / 2, 
             bar.get_height(), 
             int(bar.get_height()), 
             ha='center', 
             va='bottom', 
             fontsize=12)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_ladera.max() * 1.5)  # Aumentar un 50% el límite superior del eje Y

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR Y VEGETACIÓN¶

In [18]:
# Obtener los valores únicos y su conteo en la columna 'comun_veg'
comun_veg_counts = df_date['comun_veg'].value_counts()

# Mostrar el resultado
print(comun_veg_counts)
comun_veg
Herbaceo Subarbustivo                                                                               2019
Arbustal Nativo                                                                                     1202
E18:: Colliguaya integerrima,Trevoa patagonica y Nassauvia axillaris                                 443
F5: Stipa spp. con Mulinum spinosum y Colliguaya integerrima                                         202
Ñire                                                                                                 194
Erial                                                                                                176
Exotico-Artificial                                                                                   169
Remanente Disturbio Reciente                                                                         141
Humedales                                                                                            118
F2: Mulinum spinosum, Stipa speciosa, colliguaya integerrima y Adesmia campestris                     88
F6: Mulinum spinosum, Senecio filaginoides y diversas especies de Stipa y Festuca                     82
Lenga                                                                                                 80
F4: Diversas especies de Stipa con Mulinum spinosum, Trevoa patagonica y Colliguaya integerrima       76
E2: Larrea divaricata y Atriplex lampa                                                                75
F2: Mulinum spinosum, Stipa speciosa, Colliguaya integerrima y Adesmia campestris                     65
E21: Grindelia chiloensis, Senecio filaginoides y Stipa spp.                                          51
E16: Colliguaya integerrima, Verbena glauca y Larrea nitida                                           50
Araucaria                                                                                             47
E13: Atriplex lampa dominante                                                                         37
SR: Sin relevar                                                                                       27
D1: Semidesierto de altura                                                                            24
E19: Colliguaya integerrima, Mulinum spinosum y Nassauvia axillaris                                   22
E15: Senecio filaginoides con Larrea nitida y Stipa spp.                                              18
Matorral Mixto                                                                                        18
H2: Cortaderales                                                                                      17
Bosque Mixto                                                                                          16
E4: Larrea divaricata con Prosopis globosum                                                           16
E23: Stipa spp, Senecio filaginoides y Colliguaya integerrima                                         16
E9: Larrea divaricata y Atriplex lampa con Suaeda divaricata                                          12
E20: Fabiana imbricata y Mulinum spinosum                                                             12
X1: Vegetacion de llano aluvial de grandes rios y arroyos                                             10
E17: Colliguaya integerrima, Verbena glauca y Larrea nitida                                            9
Dy: Peladal sobre yeso                                                                                 9
G4: Diversas especies de Stipa, Poa y Festuca, con Mulinum spinosum                                    8
F1: Mulinum spinosum, Stipa spp., Nassauvia glomerulosa y Festuca pallescens                           8
Db: Peladal sobre basaltos                                                                             5
E10: Larrea divaricata y Atriplex lampa, con Haploppapus pectinatus y Verbena seriphioides             5
Coihue                                                                                                 5
X1: Vegatacion de llano aluvial de grandes rios y arroyos                                              3
F3: Diversas especies de Stipa, con Glindelia chiloensis y Cassia kurtzii                              3
U4: Urbano, densidad dispersa                                                                          3
G5: Diversas especies de Stipa con grupos aislados de Adesmia pinifolia                                3
G3: Diversas especies de Stipa y Trevoa patagonica con Haplopappus pectinatus y Mulinum spinosum       2
Cipres                                                                                                 2
Hielo-Nieve                                                                                            2
E6: Larrea divaricata , con Larrea nitida y Verbena glauca                                             2
E22: Mulinum spinosum y Stipa spp. con Verbena connatibracteata                                        1
Rauli                                                                                                  1
Chacay                                                                                                 1
U3: Urbano, densidad baja                                                                              1
Name: count, dtype: int64
In [19]:
def agrupar_vegetacion(valor):
    if valor in [
        'Herbaceo Subarbustivo',
        'E18:: Colliguaya integerrima,Trevoa patagonica y Nassauvia axillaris',
        'F5: Stipa spp. con Mulinum spinosum y Colliguaya integérrima',
        'F2: Mulinum spinosum, Stipa speciosa, colliguaya integerrima y Adesmia campestris',
        'F6: Mulinum spinosum, Senecio filaginoides y diversas especies de Stipa y Festuca',
        'F4: Diversas especies de Stipa con Mulinum spinosum, Trevoa patagonica y Colliguaya integerrima',
        'E19: Colliguaya integerrima, Mulinum spinosum y Nassauvia axillaris',
        'E23: Stipa spp, Senecio filaginoides y Colliguaya integerrima',
        'E20: Fabiana imbricata y Mulinum spinosum',
        'G4: Diversas especies de Stipa, Poa y Festuca, con Mulinum spinosum',
        'F1: Mulinum spinosum, Stipa spp., Nassauvia glomerulosa y Festuca pallescens',
        'F3: Diversas especies de Stipa, con Glindelia chiloensis y Cassia kurtzii',
        'G5: Diversas especies de Stipa con grupos aislados de Adesmia pinifolia',
        'G3: Diversas especies de Stipa y Trevoa patagonica con Haplopappus pectinatus y Mulinum spinosum',
        'E6: Larrea divaricata , con Larrea nitida y Verbena glauca',
        'E22: Mulinum spinosum y Stipa spp. con Verbena connatibracteata',
    ]:
        return 'Estepa'
    
    elif valor in [
        'Arbustal Nativo',
        'E2: Larrea divaricata y Atriplex lampa',
        'E21: Grindelia chiloensis, Senecio filaginoides y Stipa spp',
        'E16: Colliguaya integerrima, Verbena glauca y Larrea nítida',
        'E13: Atriplex lampa dominante',
        'E15: Senecio filaginoides con Larrea nitida y Stipa spp.',
        'Matorral Mixto',
        'H2: Cortaderales',
        'E4: Larrea divaricata con Prosopis globosum',
        'E9: Larrea divaricata y Atriplex lampa con Suaeda divaricata',
        'X1: Vegetacion de llano aluvial de grandes rios y arroyos',
        'E17: Colliguaya integerrima, Verbena glauca y Larrea nítida',
        'E10: Larrea divaricata y Atriplex lampa, con Haploppapus pectinatus y Verbena seriphioides',
    ]:
        return 'Desierto de Monte'
    
    elif valor in [
        'Lenga',
        'Araucaria',
        'Ñire',
        'Bosque Mixto',
        'Coihue',
        'Cipres',
        'Rauli',
        'Chacay',
    ]:
        return 'Bosque'
    
    elif valor == 'SR: Sin relevar':
        return 'NA'
    
    elif valor in [
        'Erial',
        'Dy: Peladal sobre yeso',
        'Remanente Disturbio Reciente',
    ]:
        return 'Erial'
    
    elif valor in [
        'D1: Semidesierto de altura',
        'Hielo-Nieve',
    ]:
        return 'Semi-desierto de altura'
    
    elif valor in [
        'U4: Urbano, densidad dispersa',
        'U3: Urbano, densidad baja',
    ]:
        return 'Urbano'
    
    elif valor == 'Exotico-Artificial':
        return 'Exotico-Artificial'
    
    elif valor == 'Humedales':
        return 'Humedales'
    
    else:
        return 'Otro'  # Para valores que no encajen en las categorías anteriores

# Aplicar la función a la columna 'comun_veg' y crear una nueva columna
df_incendios['vegetacion'] = df_incendios['comun_veg'].apply(agrupar_vegetacion)
In [20]:
# Contar el número de casos por categoría de vegetación
cases_per_vegetacion = df_incendios['vegetacion'].value_counts().sort_index()

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
bars = cases_per_vegetacion.plot(kind='bar', color='lightblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Tipo de Vegetación', fontsize=16)
plt.xlabel('Tipo de Vegetación', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Agregar etiquetas a las barras
for bar in bars.patches:
    plt.text(bar.get_x() + bar.get_width() / 2, 
             bar.get_height(), 
             int(bar.get_height()), 
             ha='center', 
             va='bottom', 
             fontsize=12)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_per_vegetacion.max() * 1.2)  # Aumentar un 20% el límite superior del eje Y

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

FOCOS DE CALOR POR Y DISTANCIAS A CENTROS URBANOS¶

In [21]:
# Contar el número de casos por distancia a centros urbanos
menos_3km = df_incendios['dist_aurb'].notna().sum()  # Contar todos los valores que no son NA
mas_3km = df_incendios['dist_aurb'].isna().sum()  # Contar los valores NA

# Crear una serie con los resultados
cases_summary = pd.Series([menos_3km, mas_3km], index=['A menos de 3 km de Distancia', 'A más de 3 km de Distancia'])

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
bars = cases_summary.plot(kind='bar', color='lightblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Distancia a Centros Urbanos', fontsize=16)
plt.xlabel('Categoría de Distancia', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Agregar etiquetas a las barras
for bar in bars.patches:
    plt.text(bar.get_x() + bar.get_width() / 2, 
             bar.get_height(), 
             int(bar.get_height()), 
             ha='center', 
             va='bottom', 
             fontsize=12)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_summary.max() * 1.2)  # Aumentar un 20% el límite superior del eje Y

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]:
 

FOCOS DE CALOR POR Y DISTANCIAS A RUTAS¶

In [22]:
# Contar el número de casos por distancia a rutas
menos_3km = df_incendios['dist_rut'].notna().sum()  # Contar todos los valores que no son NA
mas_3km = df_incendios['dist_rut'].isna().sum()  # Contar los valores NA

# Crear una serie con los resultados
cases_summary = pd.Series([menos_3km, mas_3km], index=['A menos de 3 km de Distancia', 'A más de 3 km de Distancia'])

# Crear el gráfico de barras
plt.figure(figsize=(12, 8))
bars = cases_summary.plot(kind='bar', color='lightblue')

# Agregar etiquetas y título
plt.title('Número de Casos por Distancia a Rutas', fontsize=16)
plt.xlabel('Categoría de Distancia', fontsize=14)
plt.ylabel('Número de Casos', fontsize=14)

# Agregar etiquetas a las barras
for bar in bars.patches:
    plt.text(bar.get_x() + bar.get_width() / 2, 
             bar.get_height(), 
             int(bar.get_height()), 
             ha='center', 
             va='bottom', 
             fontsize=12)

# Ajustar los límites del eje Y para agregar espacio extra en la parte superior
plt.ylim(0, cases_summary.max() * 1.2)  # Aumentar un 20% el límite superior del eje Y

# Mostrar el gráfico
plt.tight_layout()
plt.show()
No description has been provided for this image

MAPA INCENDIOS¶

In [23]:
df_loc = df_incendios.loc[(~df_incendios.LATITUDE.isna()) & (~df_incendios.LONGITUDE.isna())]
In [24]:
df_loc[['LATITUDE', 'LONGITUDE']].describe()
Out[24]:
LATITUDE LONGITUDE
count 5596.000000 5596.000000
mean -38.537225 -70.681941
std 0.876694 0.349069
min -41.056900 -71.943400
25% -38.896425 -70.829325
50% -38.336950 -70.730000
75% -37.926025 -70.505125
max -36.256800 -69.211700
In [25]:
def create_map(df_loc, latitude, longitude, zoom, tiles='OpenStreetMap'):
    """
    Generate a Folium Map with clustered markers of accident locations.
    """
    world_map = folium.Map(location=[latitude, longitude], zoom_start=zoom, tiles=tiles)
    marker_cluster = MarkerCluster().add_to(world_map)

    # Iterate over the DataFrame rows and add each marker to the cluster
    for idx, row in df_loc.iterrows():
        folium.Marker(
            location=[row['LATITUDE'], row['LONGITUDE']],
            # You can add more attributes to your marker here, such as a popup
            popup=f"Lat, Lng: {row['LATITUDE']}, {row['LONGITUDE']}"
        ).add_to(marker_cluster)

    return world_map

MAPA CLUSTERS¶

In [26]:
#Create and display a Folium map with clustered markers for accident locations 
# Assuming df_loc is a pandas DataFrame containing accident locations
# Ensure that the column 'Start_Lat' exists in the DataFrame 'df_loc' and is spelled correctly
# For example, if the column is named 'Start_Lat', ensure it is spelled exactly the same way in the DataFrame
map_nqn = create_map(df_loc, -38.50, -68.9, 6)

MAPA COMPLETO¶

In [27]:
def create_map_with_layers(df_loc, latitude, longitude, zoom, output_file='map_neuquen_layers.html'):
    """
    Generate a Folium Map with various layers, with tooltips showing only aliases and values.
    """
    # Create the base map
    world_map = folium.Map(location=[latitude, longitude], zoom_start=zoom, tiles='OpenStreetMap')

    # Add the Esri satellite image layer (hidden by default)
    folium.TileLayer(
        tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
        name='Esri Satellite',
        attr='Tiles © Esri',
        overlay=True,
        control=True,
        show=False
    ).add_to(world_map)
    
    # Add clustered markers (visible by default)
    marker_cluster = MarkerCluster(name='Markers', show=True).add_to(world_map)
    for idx, row in df_loc.iterrows():
        popup_text = (f"Tipo: {row['comun_veg']}, Fecha: {row['ACQ_DATE']}<br>"
                      f"Altura: {row['dem_nqn_re']}, Departamento: {row['nombre']}<br>"
                      f"DistCU: {row['dist_aurb']}, DistRutas: {row['dist_rut']}")
        folium.Marker(
            location=[row['LATITUDE'], row['LONGITUDE']],
            popup=folium.Popup(popup_text, max_width=300)
        ).add_to(marker_cluster)

    # Add heatmap layer (visible by default)
    heat_data = [[row['LATITUDE'], row['LONGITUDE']] for index, row in df_loc.iterrows()]
    HeatMap(heat_data, min_opacity=0.5, max_zoom=18, radius=10, blur=15, name='Heatmap', show=True).add_to(world_map)

    # Load and add GeoJSON layers (hidden by default)
    folium.GeoJson(
        'D:/Documents/GitHub/OPGR/Incendios/geojson/huellas_arreo.geojson',
        name='Huellas de Arreo',
        style_function=lambda x: {'color': 'blue', 'weight': 2},
        show=True
    ).add_to(world_map)
    
    folium.GeoJson(
        'D:/Documents/GitHub/OPGR/Incendios/geojson/rutas_nqn.geojson',
        name='Rutas de Neuquén',
        style_function=lambda x: {'color': 'red', 'weight': 2},
        show=True
    ).add_to(world_map)

    # Polygons with tooltips
    gdf_urbanos = gpd.read_file('D:/Documents/GitHub/OPGR/Incendios/geojson/centros_urbanos_nqn.geojson')
    folium.GeoJson(
        gdf_urbanos,
        name='Centros Urbanos',
        style_function=lambda x: {'color': 'green', 'fillColor': 'green', 'fillOpacity': 0.5},
        tooltip=folium.GeoJsonTooltip(fields=['fna'], aliases=['Localidad']),
        show=True
    ).add_to(world_map)

    # Points with tooltips
    gdf_brigadas = gpd.read_file('D:/Documents/GitHub/OPGR/Incendios/geojson/brigadas_forestales.geojson')
    folium.GeoJson(
        gdf_brigadas,
        name='Brigadas Forestales',
        style_function=lambda x: {'color': 'orange', 'fillOpacity': 0.7},
        tooltip=folium.GeoJsonTooltip(
            fields=['Localidad', 'Recur_huma', 'recur_oper', 'referente1', 'Email'],
            aliases=['Localidad:', 'Recursos Humanos:', 'Recursos Operativos:', 'Referente:', 'Email:']
        ),
        show=True
    ).add_to(world_map)

    # Add measure control and layer control
    MeasureControl(position='bottomleft', primary_length_unit='meters').add_to(world_map)
    folium.LayerControl().add_to(world_map)

    # Add title to the map
    title_html = '''
         <div style="position: fixed; top: 10px; left: 50%; transform: translate(-50%, 0); 
                     z-index: 1000; background-color: white; padding: 10px; border: 2px solid grey; 
                     border-radius: 5px; box-shadow: 2px 2px 5px grey; font-size: 18px;">
             <b>Mapa de Focos de Calor - MODIS</b>
         </div>
         '''
    world_map.get_root().html.add_child(folium.Element(title_html))

    # Export the map to an HTML file
    world_map.save(output_file)
    print(f"Mapa exportado como {output_file}")

    return world_map

# Center the map on Neuquén province (approximate coordinates)
neuquen_latitude = -38.9516
neuquen_longitude = -68.0591

# Create and export the map
map_neuquen_layers = create_map_with_layers(
    df_loc, 
    neuquen_latitude, 
    neuquen_longitude, 
    7,  # Adjust the zoom level to fit the province
    output_file='map_neuquen_layers.html'
)

map_neuquen_layers
Mapa exportado como map_neuquen_layers.html
Out[27]:
Make this Notebook Trusted to load map: File -> Trust Notebook