Gráficas de ecuaciones polares: aplicaciones en Python

Ejemplo de aplicaciones de gráficos en coordenadas polares: grafico radial y dispersión

Rigoberto Chandomi https://www.linkedin.com/in/rigobertochandomi/
2024-03-08

El gráfico de araña, también llamado gráfico de radar, gráfico web, gráfico polar y diagramas de estrellas recibe su nombre por su apariencia única. Es un gráfico que utiliza un gráfico bidimensional para mostrar una estructura de datos multidimensional. Los gráficos radiales sirven para evaluar diferentes opciones en función de múltiples variables. Permiten mostrar una o más variables en un gráfico bidimensional; cada radio corresponde a una variable. Generalmente, las métricas son características o factores que deben compararse.

Cada variable se proporciona un eje que se inicia desde el centro. Todos los ejes están dispuestos radialmente, con distancias iguales entre sí, mientras se mantiene la misma escala entre todos los ejes. Las líneas de la cuadrícula que se conectan de eje a eje, y se utilizan como una guía. Cada valor de la variable se representa a lo largo de su eje individual y todas las variables son un conjunto de datos que conectados entre sí forman un polígono.

En este primer ejemplo vamos usar datos de diferentes Shale Plays y comparar diferentes características como TOC, Espesor, Porcentaje de Kerogeno, etc.

En este primer ejemplo vamos a usar datos de diferentes Shale Plays y comparar diferentes características como TOC, Espesor, Porcentaje de Kerogeno, etc.

Los datos de este ejemplo fueron tomados de Alzahabi, A. & Soliman, M.Y. (2019) Optimization of hydraulic fracture stages and sequencing in unconventioncal formations. CRC Press

Para lo anterior primero vamos a usar la libreria matplotlib de Python. Primero cargamos los datos desde un archivo CSV con pandas. Observamos que el set de satos tiene 15 columnas y 11 observaciones, las cuales corresponden a cada formación Shale.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings 

warnings.filterwarnings("ignore")

data_Shale = pd.read_csv('Datos_Shale.csv')
print(data_Shale)
    No   Shale Plays  TOC Weight  ...  Average No of Stages  Clay  Kerogen
0    1        Antrim        5.50  ...                    12  10.1     8.89
1    2        Bakken       10.00  ...                    30  10.0    12.00
2    3       Barnett        4.50  ...                     9  30.0     4.00
3    4    Eagle Ford        4.50  ...                    16  20.0    11.00
4    5  Fayetteville        6.75  ...                    35  15.0     7.49
5    6   Haynesville        3.00  ...                    15  39.0     8.00
6    7    Horn River        3.00  ...                    18  53.0     7.13
7    8     Marcellus        3.25  ...                    30  22.5     5.10
8    9    New Albany       12.50  ...                    12  17.0     7.71
9   10          Ohio        2.35  ...                    15  36.0     7.04
10  11      Woodford        7.00  ...                    10  16.0    11.50

[11 rows x 15 columns]

Como se explica en código, debemos de definir el punto dentro de los ejes x (radio) - y (ángulo), para este ejemplo el parámetro TOC corresponde al valor del eje x, y generamos una lista que divide nuestro circulo en partes iguales, de acuerdo con el número de valores de TOC, cada división corresponde a la categoría Shale Plays. De esta forma comparamos los valores de TOC de los 11 Shale Plays del conjunto de datos.


#Nombre de Shale Plays
labels= data_Shale["Shale Plays"]; 


#Datos de Carbono Organico Total
data = data_Shale["TOC Weight"]; 


# Número de variables
num_vars = len(labels);


# Ángulos de cada eje en el gráfico polar (dividimos el círculo completo en partes iguales)
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist();


# El gráfico es circular, así que necesitamos completar el círculo
data = np.concatenate((data,[data[0]]));
angles += angles[:1];


# Inicializar el subplot polar
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True));


# Dibujar una línea para cada ubicación
ax.plot(angles, data, color='blue', linewidth=2);


# Rellenar el área bajo la línea
ax.fill(angles, data, color='blue', alpha=0.25);


# Ajustar la dirección y el orden de las etiquetas (90 grados para orientación horizontal)
ax.set_theta_offset(np.pi / 2);
ax.set_theta_direction(-1);


# Cambiar las etiquetas de 0 a 360 a 1 a 14
ax.set_thetagrids(np.arange(0, 360, 360/num_vars), labels);


# Ajustar las etiquetas de los radios a la cantidad de datos 
ax.set_rgrids(np.arange(0, 15, 2), angle=0, weight='light');


plt.show();

Otra aplicación de un grafico en coordenadas polares es la visualización de datos de fractura, que son definidos por la interpretación de datos imágenes cuando se esta caracterizando un yacimiento naturalmente fracturado.

El siguiente ejemplo muestra como representar los datos de inclinación y azimuth de las fracturas abiertas en un gráfico conocido como Estereograma Polar de Schmidt

Primero cargamos los datos desde el archivo Fracture.csv, podemos ver que tenemos 5 columnas, que incluyen los datos de pozo, profundidad, azimut, ángulo y set de fracturas.


data_Fracture = pd.read_csv('Fractures.csv')
print(data_Fracture)
       Well       MD  Dip_Azimuth  Dip_Angle  Fracture_Set
0    POZO_1  3092.83       120.70      68.11             1
1    POZO_1  3099.92       289.21      65.59             1
2    POZO_1  3100.47        43.37      64.18             1
3    POZO_1  3101.00       305.60      65.76             1
4    POZO_1  3103.71        37.98      86.43             1
..      ...      ...          ...        ...           ...
631  POZO_1  3603.17        74.79      61.23             1
632  POZO_1  3603.92       292.66      34.27             1
633  POZO_1  3604.76       280.02      50.67             1
634  POZO_1  3604.94        92.62      71.73             1
635  POZO_1  3605.87       200.92      81.21             1

[636 rows x 5 columns]

# Datos para Schmidt Plot (Scatter polar plot)
dip_angles = data_Fracture['Dip_Angle'];
dip_azimuths = data_Fracture['Dip_Azimuth'];


# Crear figuras
fig, axs = plt.subplots(subplot_kw=dict(projection='polar'), figsize=(14, 7));


# Schmidt Plot
axs.scatter(np.radians(dip_azimuths), dip_angles, color='blue');
axs.set_title('Schmidt Plot');
axs.set_rmax(90);
axs.set_theta_zero_location('N');
axs.set_theta_direction(-1);


plt.show();