Gráfico de Burbujas en Python: Np como Tamaño y Wp como Color

Visualiza la ubicación, el aceite acumulado y el agua acumulada de 16 pozos con Matplotlib

Yacimientos
Producción
Python
Visualización

Crea un mapa de burbujas en Python con los datos del ejemplo en Excel: coordenadas X–Y, área proporcional a Np y color según Wp. Incluye fragmentos de código paso a paso, dataset descargable e interpretación.

Autor/a
Fecha de publicación

27 de septiembre de 2026

Del gráfico de Excel a Python

En el post de gráfico de burbuja en Excel representamos la ubicación de los pozos y su producción acumulada mediante el tamaño de las burbujas. En esta versión vamos a reproducir el ejemplo en Python y agregar una variable: la producción acumulada de agua, Wp, mediante el color.

Así podremos comparar aceite y agua acumulados sin separar los pozos en gráficos distintos:

Cuatro variables en una sola visualización. MMB significa millones de barriles.
Elemento del gráfico Variable Unidad
Posición horizontal Coordenada X / Este m
Posición vertical Coordenada Y / Norte m
Área de la burbuja Np: aceite acumulado MMB
Color de la burbuja Wp: agua acumulada MMB
Visita el canal @rigopetrodata

Tutoriales de R, Python y Excel para ingeniería petrolera

Ver canal

Los datos del ejemplo

Usaremos los mismos 16 pozos y valores del archivo Excel original. Para simplificar la lectura desde Python, también se incluye una copia en CSV con nombres cortos de columnas: Pozo, X, Y, Np, Wp y Gp. El cambio de encabezados no modifica los datos.

Primeros cuatro registros. Gp se conserva en el archivo, aunque no participa en este gráfico. MMMPC significa miles de millones de pies cúbicos.
Pozo X (m) Y (m) Np (MMB) Wp (MMB) Gp (MMMPC)
Pozo-1 569586.39 2144591.55 28.19 0.71 57.68
Pozo-2 569041.04 2145174.40 43.27 1.70 86.92
Pozo-3 569763.04 2144227.42 1.53 0.00 4.18
Pozo-4 570100.85 2144038.94 30.00 5.75 61.97

Al sumar los 16 registros del Excel obtenemos 313.87 MMB de Np, 28.81 MMB de Wp y 653.34 MMMPC de Gp. Estos totales se calcularon directamente del archivo descargable; para este tutorial tomamos los valores del archivo como referencia.

Coordenadas y fecha de corte

El post original describe X e Y como coordenadas UTM en metros, pero el archivo no especifica zona UTM, datum ni fecha de corte de los acumulados. Aquí se muestran las coordenadas tal como están, con igual escala en ambos ejes. Para superponer una cartografía real hay que confirmar el sistema de referencia; para comparar un campo propio, usar una misma fecha de corte.

Paso 1 — Leer y revisar el dataset

Descarga el CSV al final del artículo y colócalo en la carpeta de tu notebook. Ejecuta los fragmentos en orden, dentro de la misma sesión. Necesitamos pandas, NumPy y Matplotlib; si aún no los tienes, instálalos con python -m pip install pandas numpy matplotlib.

Ver código
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.read_csv("produccion_pozos.csv")
columnas = ["X", "Y", "Np", "Wp", "Gp"]
df[columnas] = df[columnas].apply(pd.to_numeric, errors="raise")

if df.empty or not np.isfinite(df[columnas].to_numpy()).all():
    raise ValueError("Revisa los datos: hay valores faltantes o no finitos.")
if df["Pozo"].isna().any() or df["Pozo"].duplicated().any():
    raise ValueError("Revisa los nombres de los pozos.")
if (df[["Np", "Wp", "Gp"]] < 0).any().any() or df["Np"].max() <= 0:
    raise ValueError("Revisa los acumulados: deben ser no negativos y Np debe tener valores positivos.")

print(df.head().to_string(index=False))
print("\nTotales del campo:")
print(df[["Np", "Wp", "Gp"]].sum().round(2))
  Pozo         X          Y    Np   Wp    Gp
Pozo-1 569586.39 2144591.55 28.19 0.71 57.68
Pozo-2 569041.04 2145174.40 43.27 1.70 86.92
Pozo-3 569763.04 2144227.42  1.53 0.00  4.18
Pozo-4 570100.85 2144038.94 30.00 5.75 61.97
Pozo-5 571025.66 2143955.86  0.95 0.00  2.10

Totales del campo:
Np    313.87
Wp     28.81
Gp    653.34
dtype: float64

Un dato faltante no se convierte en cero: primero debe revisarse en la fuente.

Paso 2 — Representar Np con el área de burbuja

El argumento s de scatter controla el área en puntos cuadrados. Usaremos \(s_i=s_{max}N_{p,i}/N_{p,max}\): un pozo con el doble de Np tendrá el doble de área, no el doble de diámetro.

Ver código
area_max = 1800
areas = area_max * df["Np"] / df["Np"].max()

fig, ax = plt.subplots(figsize=(10, 7))
ax.scatter(df["X"], df["Y"], s=areas,
           color="#2C7FB8", edgecolors="#273746", linewidths=0.6)
ax.set_xlabel("Coordenada X / Este (m)")
ax.set_ylabel("Coordenada Y / Norte (m)")
ax.set_title("Producción acumulada de aceite por pozo")
ax.set_aspect("equal", adjustable="box")
ax.ticklabel_format(style="plain", useOffset=False)
ax.margins(0.15)
ax.grid(alpha=0.2)
ax.set_axisbelow(True)
plt.tight_layout()
plt.show()
Figura 1: Ubicación de los pozos y aceite acumulado representado por el área.

area_max cambia únicamente la presentación. En el siguiente paso agregamos las etiquetas y las leyendas para interpretar los valores.

Paso 3 — Agregar Wp como color, etiquetas y leyendas

Pasamos Wp al argumento c y usamos la paleta secuencial viridis. La escala comienza en cero, por lo que los pozos sin agua acumulada también aparecen. Una barra de color representa Wp y una leyenda de círculos representa Np.

Reutilizamos df, areas y area_max del paso anterior. Agregamos el color con c=df["Wp"], una barra de color y los nombres con un mismo desplazamiento para todos los pozos.

Ver código
fig, ax = plt.subplots(figsize=(10, 7))

# Área: Np. Color: Wp.
puntos = ax.scatter(
    df["X"], df["Y"], s=areas, c=df["Wp"],
    cmap="viridis", vmin=0, edgecolors="black"
)
fig.colorbar(puntos, ax=ax, label="Wp (MMB)")

# Nombres de los pozos.
for pozo in df.itertuples():
    ax.annotate(pozo.Pozo, (pozo.X, pozo.Y),
                xytext=(5, 5), textcoords="offset points", fontsize=9)

# Círculos de referencia con la misma escala de área.
for np_ref in [10, 30, 60]:
    ax.scatter([], [], s=area_max * np_ref / df["Np"].max(),
               color="lightgray", edgecolors="black", label=str(np_ref))
ax.legend(title="Np (MMB)", loc="upper right", labelspacing=2.5)

ax.set_xlabel("Coordenada X / Este (m)")
ax.set_ylabel("Coordenada Y / Norte (m)")
ax.set_title("Producción acumulada: tamaño = Np, color = Wp")
ax.set_aspect("equal", adjustable="box")
ax.ticklabel_format(style="plain", useOffset=False)
ax.margins(0.15)
plt.tight_layout()
plt.show()
Pozo-10 tiene la mayor burbuja y Pozo-4 el mayor acumulado de agua.
Figura 2: Mapa de producción: área proporcional a Np y color según Wp.
Leer ambas escalas

El color indica agua acumulada y el área indica aceite acumulado. Los círculos de la leyenda representan 10, 30 y 60 MMB de Np. Todos los pozos de este ejemplo tienen Np positivo; un Np igual a cero tendría área cero. Los ajustes finos de etiquetas y presentación pueden trabajarse después, en un video o curso.

¿Cómo interpretar el resultado?

Pozo-10 tiene la burbuja más grande: 63.20 MMB de Np. Su Wp es 2.29 MMB, por lo que no aparece con el color del máximo de agua.

Pozo-4 acumula 30.00 MMB de Np y 5.75 MMB de Wp. Aunque su burbuja es menor que la de Pozo-10, alcanza el extremo superior de la escala de color. El gráfico permite reconocer que el mayor acumulado de aceite y el mayor acumulado de agua corresponden a pozos distintos.

Pozo-6 también destaca por agua, con 4.90 MMB de Wp frente a 16.72 MMB de Np. Los pozos 3, 5, 12 y 16 registran Wp igual a cero en el archivo y aparecen en el extremo inferior de la escala.

Wp no es corte de agua

El color representa un volumen acumulado, no una fracción ni una tasa actual. Un Wp alto puede relacionarse con más tiempo de producción o con mayores volúmenes manejados; por sí solo no demuestra irrupción de agua ni canalización.

Para evaluar la situación actual se necesita el historial y, cuando corresponda, el corte de agua calculado con tasas compatibles: \(f_w=q_w/(q_o+q_w)\). Tampoco debe confundirse ese indicador con la fracción acumulada \(W_p/(N_p+W_p)\).

Este mapa sirve para seleccionar pozos que merecen una revisión del historial. Puedes complementarlo con el dashboard de producción y comparar periodos de operación, condiciones de medición y comportamiento temporal antes de proponer una explicación.

Adaptarlo a otros campos

  • Mantén una fila por pozo y acumulados en las mismas unidades y fecha de corte.
  • Para usar Gp como tamaño, cambia la variable de área y su leyenda, incluyendo las unidades.
  • Para comparar fechas o campos, fija la misma referencia de tamaño y los mismos límites de color en todos los mapas. Normalizar cada figura por separado puede hacer que volúmenes distintos parezcan iguales.
  • Si los ceros significan “sin dato” en tu fuente, corrígelos antes del gráfico; el código los interpreta como valores reales.

Descarga del dataset

Descargar los datos de los 16 pozos en CSV.

Referencias


🛒
Propiedades De Los Fluidos Del Yacimiento

Disponible en Mercado Libre

Ver oferta →