well-log-toolkit 0.1.114__tar.gz → 0.1.116__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/PKG-INFO +1 -1
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/pyproject.toml +1 -1
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/manager.py +19 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/visualization.py +128 -48
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/PKG-INFO +1 -1
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/README.md +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/setup.cfg +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/__init__.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/exceptions.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/las_file.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/operations.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/property.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/regression.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/statistics.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/utils.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit/well.py +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/SOURCES.txt +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/dependency_links.txt +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/requires.txt +0 -0
- {well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "well-log-toolkit"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.116"
|
|
8
8
|
description = "Fast LAS file processing with lazy loading and filtering for well log analysis"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -2466,6 +2466,9 @@ class WellDataManager:
|
|
|
2466
2466
|
depth_range: Optional[tuple[float, float]] = None,
|
|
2467
2467
|
show_colorbar: bool = True,
|
|
2468
2468
|
show_legend: bool = True,
|
|
2469
|
+
regression: Optional[Union[str, dict]] = None,
|
|
2470
|
+
regression_by_color: Optional[Union[str, dict]] = None,
|
|
2471
|
+
regression_by_group: Optional[Union[str, dict]] = None,
|
|
2469
2472
|
) -> 'Crossplot':
|
|
2470
2473
|
"""
|
|
2471
2474
|
Create a multi-well crossplot.
|
|
@@ -2531,6 +2534,19 @@ class WellDataManager:
|
|
|
2531
2534
|
Show colorbar when using color mapping. Default: True
|
|
2532
2535
|
show_legend : bool, optional
|
|
2533
2536
|
Show legend. Default: True
|
|
2537
|
+
regression : str or dict, optional
|
|
2538
|
+
Regression type to apply to all data points. Can be a string (e.g., "linear") or
|
|
2539
|
+
dict with keys: type, line_color, line_width, line_style, line_alpha, x_range.
|
|
2540
|
+
Default: None
|
|
2541
|
+
regression_by_color : str or dict, optional
|
|
2542
|
+
Regression type to apply separately for each color group in the plot. Creates
|
|
2543
|
+
separate regression lines based on what determines colors in the visualization:
|
|
2544
|
+
explicit color mapping if specified, otherwise shape groups (e.g., wells when
|
|
2545
|
+
shape='well'). Accepts string or dict format. Default: None
|
|
2546
|
+
regression_by_group : str or dict, optional
|
|
2547
|
+
Regression type to apply separately for each well. Creates separate
|
|
2548
|
+
regression lines for each well. Accepts string or dict format.
|
|
2549
|
+
Default: None
|
|
2534
2550
|
|
|
2535
2551
|
Returns
|
|
2536
2552
|
-------
|
|
@@ -2608,6 +2624,9 @@ class WellDataManager:
|
|
|
2608
2624
|
depth_range=depth_range,
|
|
2609
2625
|
show_colorbar=show_colorbar,
|
|
2610
2626
|
show_legend=show_legend,
|
|
2627
|
+
regression=regression,
|
|
2628
|
+
regression_by_color=regression_by_color,
|
|
2629
|
+
regression_by_group=regression_by_group,
|
|
2611
2630
|
)
|
|
2612
2631
|
|
|
2613
2632
|
def __repr__(self) -> str:
|
|
@@ -2827,9 +2827,10 @@ class Crossplot:
|
|
|
2827
2827
|
dict with keys: type, line_color, line_width, line_style, line_alpha, x_range.
|
|
2828
2828
|
Default: None
|
|
2829
2829
|
regression_by_color : str or dict, optional
|
|
2830
|
-
Regression type to apply separately for each color group. Creates
|
|
2831
|
-
regression lines
|
|
2832
|
-
|
|
2830
|
+
Regression type to apply separately for each color group in the plot. Creates
|
|
2831
|
+
separate regression lines based on what determines colors in the visualization:
|
|
2832
|
+
explicit color mapping if specified, otherwise shape groups (e.g., wells when
|
|
2833
|
+
shape='well'). Accepts string or dict format. Default: None
|
|
2833
2834
|
regression_by_group : str or dict, optional
|
|
2834
2835
|
Regression type to apply separately for each group (well or shape). Creates
|
|
2835
2836
|
separate regression lines for each well or shape category. Accepts string or dict.
|
|
@@ -2961,6 +2962,9 @@ class Crossplot:
|
|
|
2961
2962
|
self._regressions = {}
|
|
2962
2963
|
self.regression_lines = {}
|
|
2963
2964
|
|
|
2965
|
+
# Pending regressions (added before plot() is called)
|
|
2966
|
+
self._pending_regressions = []
|
|
2967
|
+
|
|
2964
2968
|
# Data cache
|
|
2965
2969
|
self._data = None
|
|
2966
2970
|
|
|
@@ -3159,53 +3163,70 @@ class Crossplot:
|
|
|
3159
3163
|
config = self._parse_regression_config(self.regression_by_color)
|
|
3160
3164
|
reg_type = config['type']
|
|
3161
3165
|
|
|
3162
|
-
|
|
3163
|
-
|
|
3166
|
+
# Determine grouping column based on what's being used for colors in the plot
|
|
3167
|
+
group_column = None
|
|
3168
|
+
group_label = None
|
|
3169
|
+
|
|
3170
|
+
if self.color and 'color_val' in data.columns:
|
|
3171
|
+
# User specified explicit color mapping
|
|
3172
|
+
group_column = 'color_val'
|
|
3173
|
+
group_label = self.color
|
|
3174
|
+
elif self.shape == "well" and 'well' in data.columns:
|
|
3175
|
+
# When shape="well", each well gets a different color in the plot
|
|
3176
|
+
group_column = 'well'
|
|
3177
|
+
group_label = 'well'
|
|
3178
|
+
elif self.shape and self.shape != "well" and 'shape_val' in data.columns:
|
|
3179
|
+
# When shape is a property, each shape group gets a different color
|
|
3180
|
+
group_column = 'shape_val'
|
|
3181
|
+
group_label = self.shape
|
|
3182
|
+
|
|
3183
|
+
if group_column is None:
|
|
3184
|
+
warnings.warn(
|
|
3185
|
+
"regression_by_color specified but no color grouping detected in plot. "
|
|
3186
|
+
"Use color=<property>, shape='well', or shape=<property> parameter."
|
|
3187
|
+
)
|
|
3164
3188
|
else:
|
|
3165
|
-
#
|
|
3166
|
-
if 'color_val'
|
|
3167
|
-
# For continuous
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3189
|
+
# Check if color is categorical (not continuous like depth)
|
|
3190
|
+
if group_column == 'color_val' and (self.color == 'depth' or pd.api.types.is_numeric_dtype(data[group_column])):
|
|
3191
|
+
# For continuous values, we can't create separate regressions
|
|
3192
|
+
warnings.warn(
|
|
3193
|
+
f"regression_by_color requires categorical color mapping, "
|
|
3194
|
+
f"but '{self.color}' is continuous. Use regression_by_group instead."
|
|
3195
|
+
)
|
|
3196
|
+
else:
|
|
3197
|
+
# Categorical values - group and create regressions
|
|
3198
|
+
color_groups = data.groupby(group_column)
|
|
3199
|
+
n_groups = len(color_groups)
|
|
3200
|
+
|
|
3201
|
+
# Validate regression count
|
|
3202
|
+
if regression_count + n_groups > total_points / 2:
|
|
3203
|
+
raise ValueError(
|
|
3204
|
+
f"Too many regression lines requested: {regression_count + n_groups} lines "
|
|
3205
|
+
f"for {total_points} data points (average < 2 points per line). "
|
|
3206
|
+
f"Reduce the number of groups or use a different regression strategy."
|
|
3174
3207
|
)
|
|
3175
|
-
else:
|
|
3176
|
-
# Categorical color values
|
|
3177
|
-
color_groups = data.groupby('color_val')
|
|
3178
|
-
n_groups = len(color_groups)
|
|
3179
|
-
|
|
3180
|
-
# Validate regression count
|
|
3181
|
-
if regression_count + n_groups > total_points / 2:
|
|
3182
|
-
raise ValueError(
|
|
3183
|
-
f"Too many regression lines requested: {regression_count + n_groups} lines "
|
|
3184
|
-
f"for {total_points} data points (average < 2 points per line). "
|
|
3185
|
-
f"Reduce the number of groups or use a different regression strategy."
|
|
3186
|
-
)
|
|
3187
3208
|
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
+
for idx, (group_name, group_data) in enumerate(color_groups):
|
|
3210
|
+
x_vals = group_data['x'].values
|
|
3211
|
+
y_vals = group_data['y'].values
|
|
3212
|
+
mask = np.isfinite(x_vals) & np.isfinite(y_vals)
|
|
3213
|
+
if np.sum(mask) >= 2:
|
|
3214
|
+
# Copy config and set default line color if not specified
|
|
3215
|
+
group_config = config.copy()
|
|
3216
|
+
if 'line_color' not in group_config:
|
|
3217
|
+
group_config['line_color'] = regression_colors[color_idx % len(regression_colors)]
|
|
3218
|
+
|
|
3219
|
+
# Skip legend update for all but last regression
|
|
3220
|
+
is_last = (idx == n_groups - 1)
|
|
3221
|
+
self._add_group_regression(
|
|
3222
|
+
x_vals[mask], y_vals[mask],
|
|
3223
|
+
reg_type,
|
|
3224
|
+
name=f"{group_label}={group_name}",
|
|
3225
|
+
config=group_config,
|
|
3226
|
+
update_legend=is_last
|
|
3227
|
+
)
|
|
3228
|
+
regression_count += 1
|
|
3229
|
+
color_idx += 1
|
|
3209
3230
|
|
|
3210
3231
|
# Add regression by groups (well or shape)
|
|
3211
3232
|
if self.regression_by_group:
|
|
@@ -3355,6 +3376,51 @@ class Crossplot:
|
|
|
3355
3376
|
# Add automatic regressions if specified
|
|
3356
3377
|
self._add_automatic_regressions(data)
|
|
3357
3378
|
|
|
3379
|
+
# Apply pending regressions (added via add_regression() before plot() was called)
|
|
3380
|
+
if self._pending_regressions:
|
|
3381
|
+
for pending in self._pending_regressions:
|
|
3382
|
+
# Get the already-fitted regression object
|
|
3383
|
+
reg_type = pending['regression_type']
|
|
3384
|
+
reg_name = pending['name'] if pending['name'] else reg_type
|
|
3385
|
+
|
|
3386
|
+
# Retrieve stored regression
|
|
3387
|
+
if reg_type in self._regressions and reg_name in self._regressions[reg_type]:
|
|
3388
|
+
reg = self._regressions[reg_type][reg_name]
|
|
3389
|
+
|
|
3390
|
+
# Draw the regression line
|
|
3391
|
+
try:
|
|
3392
|
+
x_line, y_line = reg.get_plot_data(x_range=pending['x_range'], num_points=200)
|
|
3393
|
+
except ValueError as e:
|
|
3394
|
+
warnings.warn(f"Could not generate plot data for {reg_type} regression: {e}")
|
|
3395
|
+
continue
|
|
3396
|
+
|
|
3397
|
+
# Create label
|
|
3398
|
+
label_parts = [reg_name]
|
|
3399
|
+
if pending['show_equation']:
|
|
3400
|
+
label_parts.append(reg.equation())
|
|
3401
|
+
if pending['show_r2']:
|
|
3402
|
+
label_parts.append(f"R² = {reg.r_squared:.4f}")
|
|
3403
|
+
label = "\n".join(label_parts)
|
|
3404
|
+
|
|
3405
|
+
# Plot line
|
|
3406
|
+
line = self.ax.plot(
|
|
3407
|
+
x_line, y_line,
|
|
3408
|
+
color=pending['line_color'],
|
|
3409
|
+
linewidth=pending['line_width'],
|
|
3410
|
+
linestyle=pending['line_style'],
|
|
3411
|
+
alpha=pending['line_alpha'],
|
|
3412
|
+
label=label
|
|
3413
|
+
)[0]
|
|
3414
|
+
|
|
3415
|
+
self.regression_lines[reg_name] = line
|
|
3416
|
+
|
|
3417
|
+
# Update legend once after all pending regressions
|
|
3418
|
+
if self.ax is not None:
|
|
3419
|
+
self.ax.legend(loc='best', frameon=True, framealpha=0.9, edgecolor='black')
|
|
3420
|
+
|
|
3421
|
+
# Clear pending list
|
|
3422
|
+
self._pending_regressions = []
|
|
3423
|
+
|
|
3358
3424
|
# Tight layout
|
|
3359
3425
|
self.fig.tight_layout()
|
|
3360
3426
|
|
|
@@ -3575,7 +3641,7 @@ class Crossplot:
|
|
|
3575
3641
|
reg_name = name if name else regression_type
|
|
3576
3642
|
self._store_regression(regression_type, reg_name, reg)
|
|
3577
3643
|
|
|
3578
|
-
# Plot regression line if figure exists
|
|
3644
|
+
# Plot regression line if figure exists, otherwise store for later
|
|
3579
3645
|
if self.ax is not None:
|
|
3580
3646
|
# Get plot data using the regression helper method
|
|
3581
3647
|
try:
|
|
@@ -3606,6 +3672,20 @@ class Crossplot:
|
|
|
3606
3672
|
|
|
3607
3673
|
# Update legend
|
|
3608
3674
|
self.ax.legend(loc='best', frameon=True, framealpha=0.9, edgecolor='black')
|
|
3675
|
+
else:
|
|
3676
|
+
# Store for later when plot() is called
|
|
3677
|
+
self._pending_regressions.append({
|
|
3678
|
+
'regression_type': regression_type,
|
|
3679
|
+
'name': name,
|
|
3680
|
+
'line_color': line_color,
|
|
3681
|
+
'line_width': line_width,
|
|
3682
|
+
'line_style': line_style,
|
|
3683
|
+
'line_alpha': line_alpha,
|
|
3684
|
+
'show_equation': show_equation,
|
|
3685
|
+
'show_r2': show_r2,
|
|
3686
|
+
'x_range': x_range,
|
|
3687
|
+
'kwargs': kwargs
|
|
3688
|
+
})
|
|
3609
3689
|
|
|
3610
3690
|
return self
|
|
3611
3691
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/requires.txt
RENAMED
|
File without changes
|
{well_log_toolkit-0.1.114 → well_log_toolkit-0.1.116}/well_log_toolkit.egg-info/top_level.txt
RENAMED
|
File without changes
|