well-log-toolkit 0.1.120__py3-none-any.whl → 0.1.122__py3-none-any.whl

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.
@@ -104,7 +104,10 @@ class LasFile:
104
104
  source_name: str = 'external_df',
105
105
  unit_mappings: Optional[dict[str, str]] = None,
106
106
  type_mappings: Optional[dict[str, str]] = None,
107
- label_mappings: Optional[dict[str, dict[int, str]]] = None
107
+ label_mappings: Optional[dict[str, dict[int, str]]] = None,
108
+ color_mappings: Optional[dict[str, dict[int, str]]] = None,
109
+ style_mappings: Optional[dict[str, dict[int, str]]] = None,
110
+ thickness_mappings: Optional[dict[str, dict[int, float]]] = None
108
111
  ) -> 'LasFile':
109
112
  """
110
113
  Create a LasFile object from a DataFrame.
@@ -123,6 +126,12 @@ class LasFile:
123
126
  Mapping of column names to 'continuous' or 'discrete'
124
127
  label_mappings : dict[str, dict[int, str]], optional
125
128
  Label mappings for discrete properties
129
+ color_mappings : dict[str, dict[int, str]], optional
130
+ Color mappings for discrete property values
131
+ style_mappings : dict[str, dict[int, str]], optional
132
+ Style mappings for discrete property values
133
+ thickness_mappings : dict[str, dict[int, float]], optional
134
+ Thickness mappings for discrete property values
126
135
 
127
136
  Returns
128
137
  -------
@@ -148,6 +157,9 @@ class LasFile:
148
157
  unit_mappings = unit_mappings or {}
149
158
  type_mappings = type_mappings or {}
150
159
  label_mappings = label_mappings or {}
160
+ color_mappings = color_mappings or {}
161
+ style_mappings = style_mappings or {}
162
+ thickness_mappings = thickness_mappings or {}
151
163
 
152
164
  # Create instance without parsing file
153
165
  instance = cls(source_name, _from_dataframe=True)
@@ -176,7 +188,7 @@ class LasFile:
176
188
  'multiplier': None
177
189
  }
178
190
 
179
- # Set parameter info (discrete labels)
191
+ # Set parameter info (discrete labels and metadata)
180
192
  if label_mappings:
181
193
  discrete_props = ','.join(sorted(label_mappings.keys()))
182
194
  instance.parameter_info['DISCRETE_PROPS'] = discrete_props
@@ -186,6 +198,27 @@ class LasFile:
186
198
  param_name = f"{prop_name}_{value}"
187
199
  instance.parameter_info[param_name] = label
188
200
 
201
+ # Add color mappings to parameter section
202
+ if color_mappings:
203
+ for prop_name, colors in color_mappings.items():
204
+ for value, color in colors.items():
205
+ param_name = f"{prop_name}_{value}_COLOR"
206
+ instance.parameter_info[param_name] = color
207
+
208
+ # Add style mappings to parameter section
209
+ if style_mappings:
210
+ for prop_name, styles in style_mappings.items():
211
+ for value, style in styles.items():
212
+ param_name = f"{prop_name}_{value}_STYLE"
213
+ instance.parameter_info[param_name] = style
214
+
215
+ # Add thickness mappings to parameter section
216
+ if thickness_mappings:
217
+ for prop_name, thicknesses in thickness_mappings.items():
218
+ for value, thickness in thicknesses.items():
219
+ param_name = f"{prop_name}_{value}_THICKNESS"
220
+ instance.parameter_info[param_name] = str(thickness)
221
+
189
222
  # Set data directly
190
223
  instance._data = df.copy()
191
224
 
well_log_toolkit/well.py CHANGED
@@ -335,9 +335,17 @@ class Well:
335
335
  # Mark source as modified
336
336
  self._sources[source_name]['modified'] = True
337
337
 
338
- def load_las(self, las: Union[LasFile, str, Path], sampled: bool = False, resample_method: Optional[str] = None, merge: bool = False) -> 'Well':
338
+ def load_las(
339
+ self,
340
+ las: Union[LasFile, str, Path, list[Union[str, Path]]],
341
+ sampled: bool = False,
342
+ resample_method: Optional[str] = None,
343
+ merge: bool = False,
344
+ combine: Optional[str] = None,
345
+ source_name: Optional[str] = None
346
+ ) -> 'Well':
339
347
  """
340
- Load LAS file into this well, organized by source.
348
+ Load LAS file(s) into this well, organized by source.
341
349
 
342
350
  Properties are grouped by source (LAS file). The source name is derived
343
351
  from the filename stem (without extension), sanitized for Python attribute
@@ -346,8 +354,8 @@ class Well:
346
354
 
347
355
  Parameters
348
356
  ----------
349
- las : Union[LasFile, str, Path]
350
- Either a LasFile instance or path to LAS file
357
+ las : Union[LasFile, str, Path, list[Union[str, Path]]]
358
+ Either a LasFile instance, path to LAS file, or list of LAS file paths
351
359
  sampled : bool, default False
352
360
  If True, mark all properties from this source as 'sampled' type.
353
361
  Use this for core plug data or other point measurements where
@@ -365,6 +373,15 @@ class Well:
365
373
  properties into the existing source instead of overwriting it.
366
374
  When merging with incompatible depth grids, resample_method must be specified.
367
375
  If False (default), existing source is overwritten with warning.
376
+ combine : str, optional
377
+ When loading multiple files (list), combine them into a single source:
378
+ - None (default): Load files as separate sources, no combining
379
+ - 'match': Combine using match method (safest, errors on mismatch)
380
+ - 'resample': Combine using resample method (interpolates to first file)
381
+ - 'concat': Combine using concat method (merges all unique depths)
382
+ source_name : str, optional
383
+ Name for combined source when combine is specified. If not specified,
384
+ uses 'combined_match', 'combined_resample', or 'combined_concat'
368
385
 
369
386
  Returns
370
387
  -------
@@ -381,23 +398,70 @@ class Well:
381
398
 
382
399
  Examples
383
400
  --------
384
- >>> well = manager.well_36_7_5_B
401
+ >>> # Load single file
385
402
  >>> well.load_las("36_7-5_B_CorePor.las") # Source name: "CorePor"
386
- >>> well.load_las("36_7-5_B_Log.las") # Source name: "Log"
387
- >>> well.load_las("formation_tops.las") # Source name: "formation_tops"
403
+
404
+ >>> # Load multiple files as separate sources
405
+ >>> well.load_las(["file1.las", "file2.las", "file3.las"])
406
+ >>> print(well.sources) # ['file1', 'file2', 'file3']
407
+
408
+ >>> # Load and combine multiple files
409
+ >>> well.load_las(
410
+ ... ["file1.las", "file2.las", "file3.las"],
411
+ ... combine="match",
412
+ ... source_name="CombinedLogs"
413
+ ... )
414
+ >>> print(well.sources) # ['CombinedLogs']
415
+
388
416
  >>> # Load core plug data as sampled
389
417
  >>> well.load_las("36_7-5_B_Core.las", sampled=True)
390
- >>> # Load data with incompatible depths
391
- >>> well.load_las("interpreted.las", resample_method='linear')
392
- >>> # Merge additional properties into existing source
418
+
419
+ >>> # Load with resample combining
420
+ >>> well.load_las(
421
+ ... ["log1.las", "log2.las"],
422
+ ... combine="resample",
423
+ ... source_name="CombinedLogs"
424
+ ... )
425
+
426
+ >>> # Merge into existing source (legacy behavior)
393
427
  >>> well.load_las("CorePor.las") # Load initial properties
394
- >>> well.load_las("CorePor_Extra.las", merge=True) # Merge new properties into "CorePor"
395
- >>> # Access by source
396
- >>> well.CorePor.PHIE
397
- >>> well.Log.GR
398
- >>> # Access directly if unique
399
- >>> well.PHIE # Error if both CorePor and Log have PHIE
428
+ >>> well.load_las("CorePor_Extra.las", merge=True) # Merge new properties
400
429
  """
430
+ # Handle list of files
431
+ if isinstance(las, list):
432
+ # Load all files as separate sources
433
+ loaded_sources = []
434
+ for las_file in las:
435
+ # Recursively call load_las for each file (without merge or combine)
436
+ self.load_las(las_file, sampled=sampled, resample_method=resample_method, merge=False, combine=None)
437
+ # Get the source name that was just created
438
+ loaded_sources.append(self.sources[-1])
439
+
440
+ # Combine if requested
441
+ if combine in {'match', 'resample', 'concat'}:
442
+ # Determine combined source name
443
+ combined_source_name = source_name or f'combined_{combine}'
444
+
445
+ # Merge all loaded sources
446
+ self.merge(
447
+ method=combine,
448
+ sources=loaded_sources,
449
+ source_name=combined_source_name
450
+ )
451
+
452
+ # Remove original sources
453
+ self.remove_source(loaded_sources)
454
+
455
+ return self
456
+
457
+ # Single file logic below
458
+ # Validate combine parameter for single file
459
+ if combine is not None:
460
+ raise ValueError(
461
+ f"combine='{combine}' is only valid when loading multiple files (list). "
462
+ f"For single file loading, use merge=True to merge into existing source."
463
+ )
464
+
401
465
  # Parse if path provided
402
466
  filepath = None
403
467
  if isinstance(las, (str, Path)):
@@ -2247,7 +2311,7 @@ class Well:
2247
2311
 
2248
2312
  df = pd.DataFrame(data)
2249
2313
 
2250
- # Create LasFile from DataFrame
2314
+ # Create LasFile from DataFrame with all metadata
2251
2315
  las = LasFile.from_dataframe(
2252
2316
  df=df,
2253
2317
  well_name=self.name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: well-log-toolkit
3
- Version: 0.1.120
3
+ Version: 0.1.122
4
4
  Summary: Fast LAS file processing with lazy loading and filtering for well log analysis
5
5
  Author-email: Kristian dF Kollsgård <kkollsg@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  well_log_toolkit/__init__.py,sha256=ilJAIIhh68pYfD9I3V53juTEJpoMN8oHpcpEFNpuXAQ,3793
2
2
  well_log_toolkit/exceptions.py,sha256=X_fzC7d4yaBFO9Vx74dEIB6xmI9Agi6_bTU3MPxn6ko,985
3
- well_log_toolkit/las_file.py,sha256=yRCIiVbdoqFzoXKRKfx7Lt11INmwB_bXdpHpwVaNpjk,52156
3
+ well_log_toolkit/las_file.py,sha256=Tj0mRfX1aX2s6uug7BBlY1m_mu3G50EGxHGzD0eEedE,53876
4
4
  well_log_toolkit/manager.py,sha256=Mc_zgC9pgbYq82msiAc0KMVmPFbCX90SZK5JfwGY4H4,102422
5
5
  well_log_toolkit/operations.py,sha256=z8j8fGBOwoJGUQFy-Vawjq9nm3OD_dUt0oaNh8yuG7o,18515
6
6
  well_log_toolkit/property.py,sha256=WOzoNQcmHCQ8moIKsnSyLgVC8s4LBu2x5IBXtFzmMe8,76236
@@ -8,8 +8,8 @@ well_log_toolkit/regression.py,sha256=7D3oI-1XVlFb-mOoHTxTTtUHERFyvQSBAzJzAGVoZn
8
8
  well_log_toolkit/statistics.py,sha256=_huPMbv2H3o9ezunjEM94mJknX5wPK8V4nDv2lIZZRw,16814
9
9
  well_log_toolkit/utils.py,sha256=O2KPq4htIoUlL74V2zKftdqqTjRfezU9M-568zPLme0,6866
10
10
  well_log_toolkit/visualization.py,sha256=xb870FG5FghU2gEkqdn1b2NbWNu07oDmFDN1Cx1HIi0,157280
11
- well_log_toolkit/well.py,sha256=-huYBLw_nEmZm_sEAiPq0_az9WFmZ-TyHmM-Vn_vxQk,99591
12
- well_log_toolkit-0.1.120.dist-info/METADATA,sha256=LxF_4YtWXQyNFXG0dOoZ0-SJaN4OJoF5o2CTiUZOS60,59810
13
- well_log_toolkit-0.1.120.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- well_log_toolkit-0.1.120.dist-info/top_level.txt,sha256=BMOo7OKLcZEnjo0wOLMclwzwTbYKYh31I8RGDOGSBdE,17
15
- well_log_toolkit-0.1.120.dist-info/RECORD,,
11
+ well_log_toolkit/well.py,sha256=u2KhhMfXkMPIOKRgH3SB3k-2knotqWdBGY4Lup31Pxc,102017
12
+ well_log_toolkit-0.1.122.dist-info/METADATA,sha256=MxrNyJ2HeEdC6VUmRFSPdVT6te10N5Buy-iJLzwHEFY,59810
13
+ well_log_toolkit-0.1.122.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ well_log_toolkit-0.1.122.dist-info/top_level.txt,sha256=BMOo7OKLcZEnjo0wOLMclwzwTbYKYh31I8RGDOGSBdE,17
15
+ well_log_toolkit-0.1.122.dist-info/RECORD,,