Skip to content

Commit

Permalink
Edit Files
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderJuestel committed Apr 8, 2024
1 parent e6d0b8c commit c5278f7
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 5 deletions.
10 changes: 8 additions & 2 deletions pyborehole/logs_las.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import copy

from pyborehole.plot import plot_well_logs as pwl
from pyborehole.utils import get_depth_ranges as gdr


class LASLogs:
Expand Down Expand Up @@ -340,6 +341,9 @@ def __init__(self,
self.df.index.rename('DEPTH', inplace=True)
self.df = self.df.reset_index()

# Getting depth ranges
self.log_ranges = gdr(self.df)

# Creating DataFrame from curve data
self.curves = pd.DataFrame(list(zip([las.curves[i]['original_mnemonic'] for i in range(len(las.curves))],
[las.curves[i]['mnemonic'] for i in range(len(las.curves))],
Expand All @@ -354,6 +358,9 @@ def __init__(self,
self.curves.at[0, 'original_mnemonic'] = 'DEPTH'
self.curves.at[0, 'mnemonic'] = 'DEPTH'

# Merging Curves DataFrame and Depth Ranges
self.curves = self.curves.merge(self.log_ranges, on='mnemonic')

# Creating DataFrame from well header
self.well_header = pd.DataFrame(list(zip([las.well[i]['mnemonic'] for i in range(len(las.well))],
[las.well[i]['unit'] for i in range(len(las.well))],
Expand Down Expand Up @@ -467,7 +474,6 @@ def plot_well_logs(self,

return fig, ax


def plot_well_log_along_path(self,
log: str,
depth_column: str = 'DEPTH',
Expand Down Expand Up @@ -1122,4 +1128,4 @@ def calculate_synthetic_seismic(self,
rc_tdom):
synth = np.apply_along_axis(lambda t0: np.convolve(t0, w, mode="same"), axis=0, arr=rc_tdom)

return synth
return synth
100 changes: 99 additions & 1 deletion pyborehole/logs_lis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import numpy as np
import matplotlib

from pyborehole.plot import plot_well_logs as pwl
from pyborehole.utils import get_depth_ranges as gdr


class LISLogs:
"""Class to initiate a Well Log Object.
Expand Down Expand Up @@ -192,16 +195,26 @@ def __init__(self,
self.df = df

# Changing the name of the depth column
self.df['DEPTH'] = self.df['DEPT']
self.df.insert(0, 'DEPTH', self.df['DEPT'])
self.df = self.df.drop('DEPT', axis=1)

# Getting depth ranges
self.log_ranges = gdr(self.df)

# Creating Curves DataFrame
self.curves = pd.DataFrame(list(zip(columns, columns, columns, units)),
columns=['original_mnemonic',
'mnemonic',
'descr',
'unit'])

# Changing name of depth column in curves DataFrame
self.curves.at[0, 'original_mnemonic'] = 'DEPTH'
self.curves.at[0, 'mnemonic'] = 'DEPTH'

# Merging Curves DataFrame and Depth Ranges
self.curves = self.curves.merge(self.log_ranges, on='mnemonic')

# Getting index of depth column
depth_column_index = columns.index('DEPT')

Expand Down Expand Up @@ -230,3 +243,88 @@ def __init__(self,
'value',
'descr'])

def plot_well_logs(self,
tracks: Union[str, list] = None,
depth_column: str = 'DEPTH',
depth_min: Union[int, float] = None,
depth_max: Union[int, float] = None,
colors: Union[str, list] = None,
add_well_tops: bool = False,
add_well_design: bool = False,
fill_between: int = None,
add_net_to_gross: int = None,
fontsize_well_tops: Union[int, float] = 12,
use_df_tdom: bool = False) -> Tuple[matplotlib.figure.Figure, matplotlib.axes.Axes]:
"""Plot well logs.
Parameters
__________
tracks : Union[str, list]
Name/s of the logs to be plotted, e.g. ``tracks='SGR'`` or ``tracks=['SGR', 'K']``.
depth_column : str, default: ``'DEPTH'``
Name of the column holding the depths, e.g. ``depth_column='DEPTH'``.
depth_min : Union[int, float]
Minimum depth to be plotted, e.g. ``depth_min=0``.
depth_max : Union[int, float]
Maximum depth to be plotted, e.g. ``depth_max=2000``.
colors : Union[str, list], default: ``None``
Colors of the logs, e.g. ``colors='black'`` or ``colors=['black', 'blue']``.
add_well_tops : bool, default: ``False``
Boolean to add well tops to the plot, e.g. ``add_well_tops=True``.
add_well_design : bool, default: ``False``
Boolean to add well design to the plot, e.g. ``add_well_design=True``.
fill_between : int, default: ``None``
Number of the axis to fill, e.g. ``fill_between=0``.
add_net_to_gross : int, default: ``None``
Number of axis to fill with the net to gross values, e.g. ``add_net_to_gross=0``.
Returns
_______
fig : matplotlib.figure.Figure
Matplotlib Figure.
ax : matplotlib.axes.Axes
Matplotlib Axes.
Raises
______
TypeError
If the wrong input data types are provided.
ValueError
If no well tops are provided but ``add_well_tops`` is set to ``True``.
ValueError
If the wrong column names are provided.
Examples
________
>>> import pyborehole
>>> from pyborehole.borehole import Borehole
>>> borehole = Borehole(name='Weisweiler R1')
>>> borehole.init_properties(location=(6.313031, 50.835676), crs='EPSG:4326', altitude_above_sea_level=136)
>>> borehole.add_well_logs(path='Well_logs.las')
>>> borehole.logs.plot_well_logs(tracks=['SGR', 'CAL'], depth_column='DEPTH', colors=['black', 'red'])
See Also
________
plot_well_log_along_path : Plot well log along path.
calculate_vshale : Calculate Shale Volume.
calculate_vshale_linear : Calculate Shale Volume linear method.
calculate_net_to_gross : Calculate net to gross.
.. versionadded:: 0.0.1
"""

fig, ax = pwl(self,
tracks=tracks,
depth_column=depth_column,
depth_min=depth_min,
depth_max=depth_max,
colors=colors,
add_well_tops=add_well_tops,
add_well_design=add_well_design,
fill_between=fill_between,
add_net_to_gross=add_net_to_gross,
fontsize_well_tops=fontsize_well_tops,
use_df_tdom=use_df_tdom)

return fig, ax
93 changes: 91 additions & 2 deletions pyborehole/plot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union, Tuple
from typing import Union, Tuple, List
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
Expand Down Expand Up @@ -209,7 +209,7 @@ def plot_well_logs(logs,
# Creating plot
fig, ax = plt.subplots(1,
1 + j + k + l,
figsize=(1 + j + k + l * 1.8, 8),
figsize=((1 + j + k + l) * 1.8, 8),
sharey=True)

if not add_well_tops and not add_net_to_gross:
Expand Down Expand Up @@ -354,6 +354,8 @@ def plot_well_logs(logs,
'unit'].iloc[
0], color='black')

plt.tight_layout()

return fig, ax

# Creating plot if tracks is of type list
Expand Down Expand Up @@ -609,3 +611,90 @@ def plot_well_logs(logs,
ax.set_xlabel('Diameter [in]')

return fig, ax


def plot_logs_multiple_wells(wells: list,
params: List[dict]):
# Checking that the provided lists have the same length
if len(wells) != len(params):
raise ValueError('The same number of well objects and params dicts must be provided')

min_depths = []
max_depths = []
buffers = []
dfs = []

colors = ['black','black','black', 'black']

fig, ax = plt.subplots(1,
len(wells),
figsize=(len(wells) * 1.8, 8)
)

# Setting y label
ax[0].set_ylabel('Depth [m]')

for i in range(len(params)):

# Selecting depth range
if 'depth_min' not in params[i]:
depth_min = min(wells[i].logs.df[params[i]['depth_column']])
min_depths.append(depth_min)
else:
depth_min = params[i]['depth_min']
min_depths = depth_min
if 'depth_max' not in params[i]:
depth_max = max(wells[i].logs.df[params[i]['depth_column']])
max_depths.append(depth_max)
else:
depth_max = params[i]['depth_max']
max_depths = depth_max

# Setting buffer for plotting
buffer = (depth_max - depth_min) / 20
buffers.append(buffer)

# Selecting depth range
df = wells[i].logs.df[(wells[i].logs.df[params[i]['depth_column']] >= depth_min) & (
wells[i].logs.df[params[i]['depth_column']] <= depth_max)]

dfs.append(df)

ax[i].plot(dfs[i][params[i]['track']],
dfs[i][params[i]['depth_column']], color='black', linewidth=0.5)

# Setting Grid
ax[i].grid()

# Inverting y axis
ax[i].invert_yaxis()

# Setting y limits
ax[i].set_ylim(depth_max + buffer,
depth_min - buffer)

# Setting x limits
ax[i].set_xlim(params[i]['xmin'],
params[i]['xmax'])

# Setting tick params
ax[i].tick_params(top=True, labeltop=True, bottom=False, labelbottom=False)

# Setting x label position
ax[i].xaxis.set_label_position('top')

# Setting x label
ax[i].set_xlabel(params[i]['track'] + ' [%s]' %
wells[i].logs.curves[wells[i].logs.curves['original_mnemonic'] == params[i]['track']].reset_index(
drop=True)[
'unit'].iloc[0],
color='black' if isinstance(colors[i], type(None)) else colors[i])

# Setting title
ax[i].set_title(wells[i].name)

plt.tight_layout()

return fig, ax


35 changes: 35 additions & 0 deletions pyborehole/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import pandas as pd

# Defining function to get depth ranges
def get_depth_ranges(df: pd.DataFrame) -> pd.DataFrame:

# Creating empty lists
column_name_list = []
min_depth_list = []
max_depth_list = []

for i in range(len(df.columns)):
# Getting column name
column_name = df.columns[i]

# Selecting Data
data = df[[df.columns[i]] + ['DEPTH']].dropna()

# Getting minimum depth of log
min_depth = min(data.loc[:, ~data.columns.duplicated()].copy()['DEPTH'])

# Getting maximum depth of log
max_depth = max(data.loc[:, ~data.columns.duplicated()].copy()['DEPTH'])

# Appending values to list
column_name_list.append(column_name)
min_depth_list.append(min_depth)
max_depth_list.append(max_depth)

data_dict = {'mnemonic': column_name_list,
'Depth Min': min_depth_list,
'Depth Max': max_depth_list}

data_df = pd.DataFrame.from_dict(data=data_dict, orient='columns')#, columns=['original_mnemonic', 'Depth Min', 'Depth Max'])

return data_df

0 comments on commit c5278f7

Please sign in to comment.