pyckster 26.2.2__py3-none-any.whl → 26.2.3__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.
pyckster/__init__.py CHANGED
@@ -15,7 +15,7 @@ except ImportError:
15
15
  pass # matplotlib not available, that's fine
16
16
 
17
17
  # Define version and metadata in one place
18
- __version__ = "26.2.2"
18
+ __version__ = "26.2.3"
19
19
  __author__ = "Sylvain Pasquet"
20
20
  __email__ = "sylvain.pasquet@sorbonne-universite.fr"
21
21
  __license__ = "GPLv3"
pyckster/core.py CHANGED
@@ -11663,7 +11663,7 @@ class MainWindow(QMainWindow):
11663
11663
  self.skip_header_edit = QSpinBox()
11664
11664
  self.skip_header_edit.setRange(0, 1000)
11665
11665
  self.skip_header_edit.setValue(0)
11666
- self.skip_header_edit.setToolTip("Number of header lines to skip in the ASCII file")
11666
+ self.skip_header_edit.setToolTip("Number of lines to skip from the beginning of the file (counts all lines including comments)")
11667
11667
  data_layout.addRow("Skip header lines:", self.skip_header_edit)
11668
11668
 
11669
11669
  self.delimiter_edit = QLineEdit()
@@ -11738,7 +11738,24 @@ class MainWindow(QMainWindow):
11738
11738
  successful_imports = 0
11739
11739
  failed_imports = []
11740
11740
 
11741
- for file_path in params['file_paths']:
11741
+ # Create progress dialog for batch import
11742
+ progress = None
11743
+ if len(params['file_paths']) > 1:
11744
+ progress = QProgressDialog("Importing ASCII matrices...", "Cancel", 0, len(params['file_paths']), self)
11745
+ progress.setWindowTitle("Importing ASCII Matrices")
11746
+ progress.setMinimumDuration(0)
11747
+ progress.setWindowModality(QtCore.Qt.WindowModal)
11748
+ progress.setValue(0)
11749
+ progress.show()
11750
+ QApplication.processEvents()
11751
+
11752
+ for idx, file_path in enumerate(params['file_paths']):
11753
+ if progress:
11754
+ progress.setValue(idx)
11755
+ if progress.wasCanceled():
11756
+ break
11757
+ progress.setLabelText(f"Importing file {idx+1} of {len(params['file_paths'])}...")
11758
+ QApplication.processEvents()
11742
11759
  try:
11743
11760
  # Load the ASCII matrix
11744
11761
  QApplication.processEvents()
@@ -11760,13 +11777,15 @@ class MainWindow(QMainWindow):
11760
11777
  delimiter = None # Let numpy handle it
11761
11778
 
11762
11779
  # Load the data with skiprows parameter
11780
+ # Set comments=None to disable automatic comment skipping (numpy default is comments='#')
11781
+ # This ensures skiprows counts ALL lines as documented
11763
11782
  try:
11764
- data_matrix = np.loadtxt(file_path, delimiter=delimiter, skiprows=params['skip_header'])
11783
+ data_matrix = np.loadtxt(file_path, delimiter=delimiter, skiprows=params['skip_header'], comments=None)
11765
11784
  except ValueError:
11766
11785
  # Try with different delimiters
11767
11786
  for delim in [None, ',', '\t', ' ']:
11768
11787
  try:
11769
- data_matrix = np.loadtxt(file_path, delimiter=delim, skiprows=params['skip_header'])
11788
+ data_matrix = np.loadtxt(file_path, delimiter=delim, skiprows=params['skip_header'], comments=None)
11770
11789
  break
11771
11790
  except ValueError:
11772
11791
  continue
@@ -11781,6 +11800,53 @@ class MainWindow(QMainWindow):
11781
11800
  if data_matrix.ndim == 1:
11782
11801
  data_matrix = data_matrix.reshape(-1, 1)
11783
11802
 
11803
+ # Auto-detect orientation: number of traces should typically be less than number of time samples
11804
+ # This helps prevent memory overload from incorrect orientation
11805
+ n_rows, n_cols = data_matrix.shape
11806
+ if n_cols > n_rows:
11807
+ # More columns than rows suggests wrong orientation
11808
+ # This would mean more traces than time samples, which is unusual
11809
+
11810
+ # Check if we should use "yes to all" from previous choice
11811
+ if not hasattr(self, '_transpose_yes_to_all'):
11812
+ self._transpose_yes_to_all = False
11813
+
11814
+ if self._transpose_yes_to_all:
11815
+ # Automatically transpose based on previous "yes to all" choice
11816
+ data_matrix = data_matrix.T
11817
+ params['transpose'] = not params['transpose']
11818
+ else:
11819
+ # Ask user
11820
+ msg = QMessageBox()
11821
+ msg.setIcon(QMessageBox.Warning)
11822
+ msg.setWindowTitle("Potential Orientation Issue")
11823
+ msg.setText(
11824
+ f"The matrix has {n_cols} columns and {n_rows} rows.\n\n"
11825
+ f"This would result in {n_cols} traces with {n_rows} time samples each, "
11826
+ f"which is unusual (typically, traces < time samples).\n\n"
11827
+ f"Do you want to transpose the matrix?\n"
11828
+ f"(This would give {n_rows} traces with {n_cols} samples each)"
11829
+ )
11830
+ msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
11831
+ msg.setDefaultButton(QMessageBox.Yes)
11832
+
11833
+ # Add "Yes to All" checkbox for batch imports
11834
+ yes_to_all_checkbox = None
11835
+ if len(params['file_paths']) > 1:
11836
+ yes_to_all_checkbox = QCheckBox("Apply to all remaining files")
11837
+ msg.setCheckBox(yes_to_all_checkbox)
11838
+
11839
+ result = msg.exec_()
11840
+
11841
+ # Check if "Yes to All" was selected
11842
+ if yes_to_all_checkbox and yes_to_all_checkbox.isChecked():
11843
+ self._transpose_yes_to_all = True
11844
+
11845
+ if result == QMessageBox.Yes:
11846
+ data_matrix = data_matrix.T
11847
+ # Update the effective transpose state for display later
11848
+ params['transpose'] = not params['transpose']
11849
+
11784
11850
  # Validate the data matrix
11785
11851
  if data_matrix.size == 0:
11786
11852
  raise ValueError("The loaded matrix is empty")
@@ -11850,6 +11916,10 @@ class MainWindow(QMainWindow):
11850
11916
  except Exception as e:
11851
11917
  failed_imports.append((os.path.basename(file_path), str(e)))
11852
11918
 
11919
+ # Close progress dialog
11920
+ if progress:
11921
+ progress.setValue(len(params['file_paths']))
11922
+
11853
11923
  # After processing all files, update UI and show results
11854
11924
  if successful_imports > 0:
11855
11925
  # Select the last imported file
@@ -11870,9 +11940,57 @@ class MainWindow(QMainWindow):
11870
11940
  if len(failed_imports) > 5:
11871
11941
  error_msg += f"\n\n... and {len(failed_imports) - 5} more"
11872
11942
  QMessageBox.warning(self, "Import Complete with Errors", error_msg)
11873
- else:
11874
- QMessageBox.information(self, "Import Successful",
11875
- f"Successfully imported {successful_imports} ASCII file(s)")
11943
+ elif successful_imports > 0:
11944
+ # Calculate total traces and samples for successful imports
11945
+ total_traces = 0
11946
+ total_samples = 0
11947
+ # Track different configurations
11948
+ config_counts = {} # (n_traces, n_samples): count
11949
+
11950
+ for i in range(len(self.streams) - successful_imports, len(self.streams)):
11951
+ if i >= 0 and i < len(self.trace_position) and self.trace_position[i] is not None:
11952
+ n_traces = len(self.trace_position[i])
11953
+ total_traces += n_traces
11954
+ else:
11955
+ n_traces = 0
11956
+
11957
+ if i >= 0 and i < len(self.n_sample) and self.n_sample[i] is not None:
11958
+ n_samples = self.n_sample[i]
11959
+ total_samples += n_samples
11960
+ else:
11961
+ n_samples = 0
11962
+
11963
+ # Track configuration
11964
+ config = (n_traces, n_samples)
11965
+ config_counts[config] = config_counts.get(config, 0) + 1
11966
+
11967
+ # Show detailed information
11968
+ if successful_imports == 1:
11969
+ # Single file - show detailed info
11970
+ idx = len(self.streams) - 1
11971
+ n_traces = len(self.trace_position[idx]) if idx < len(self.trace_position) and self.trace_position[idx] else 0
11972
+ n_samp = self.n_sample[idx] if idx < len(self.n_sample) and self.n_sample[idx] else 0
11973
+ QMessageBox.information(
11974
+ self, "Import Successful",
11975
+ f"Successfully imported ASCII matrix\n\n"
11976
+ f"Traces: {n_traces}\n"
11977
+ f"Samples per trace: {n_samp}\n"
11978
+ f"Orientation: {'Transposed (traces were in rows)' if params['transpose'] else 'Standard (traces in columns)'}"
11979
+ )
11980
+ else:
11981
+ # Multiple files - show configuration breakdown
11982
+ summary_msg = f"Successfully imported {successful_imports} ASCII file(s)\n\n"
11983
+
11984
+ # Show configuration breakdown
11985
+ if len(config_counts) > 0:
11986
+ for (n_traces, n_samples), count in sorted(config_counts.items()):
11987
+ summary_msg += f"• {count} file(s): {n_traces} traces × {n_samples} samples\n"
11988
+
11989
+ QMessageBox.information(self, "Import Successful", summary_msg.rstrip())
11990
+
11991
+ # Reset transpose yes-to-all flag after batch import completes
11992
+ if hasattr(self, '_transpose_yes_to_all'):
11993
+ delattr(self, '_transpose_yes_to_all')
11876
11994
 
11877
11995
  def ascii_to_obspy_stream(self, data_matrix, params):
11878
11996
  """Convert ASCII matrix to ObsPy Stream object"""
@@ -11939,7 +12057,24 @@ class MainWindow(QMainWindow):
11939
12057
  successful_imports = 0
11940
12058
  failed_imports = []
11941
12059
 
11942
- for archive_path in archive_paths:
12060
+ # Create progress dialog for batch archive import
12061
+ progress = None
12062
+ if len(archive_paths) > 1:
12063
+ progress = QProgressDialog("Importing archives...", "Cancel", 0, len(archive_paths), self)
12064
+ progress.setWindowTitle("Importing Archives")
12065
+ progress.setMinimumDuration(0)
12066
+ progress.setWindowModality(QtCore.Qt.WindowModal)
12067
+ progress.setValue(0)
12068
+ progress.show()
12069
+ QApplication.processEvents()
12070
+
12071
+ for idx, archive_path in enumerate(archive_paths):
12072
+ if progress:
12073
+ progress.setValue(idx)
12074
+ if progress.wasCanceled():
12075
+ break
12076
+ progress.setLabelText(f"Importing archive {idx+1} of {len(archive_paths)}...")
12077
+ QApplication.processEvents()
11943
12078
  try:
11944
12079
  QApplication.setOverrideCursor(Qt.WaitCursor)
11945
12080
 
@@ -12101,6 +12236,10 @@ class MainWindow(QMainWindow):
12101
12236
  finally:
12102
12237
  QApplication.restoreOverrideCursor()
12103
12238
 
12239
+ # Close progress dialog
12240
+ if progress:
12241
+ progress.setValue(len(archive_paths))
12242
+
12104
12243
  # After processing all files, update UI and show results
12105
12244
  if successful_imports > 0:
12106
12245
  # Initialize plot labels if they don't exist
@@ -12119,19 +12258,70 @@ class MainWindow(QMainWindow):
12119
12258
  # Plot the new data
12120
12259
  self.updatePlots()
12121
12260
 
12261
+ # Calculate total traces and samples for successful imports
12262
+ total_traces = 0
12263
+ total_samples = 0
12264
+ # Track different configurations
12265
+ config_counts = {} # (n_traces, n_samples): count
12266
+
12267
+ if successful_imports > 0:
12268
+ # Count traces and samples from the newly imported files
12269
+ # (last successful_imports files in the lists)
12270
+ for i in range(len(self.streams) - successful_imports, len(self.streams)):
12271
+ if i >= 0 and i < len(self.trace_position) and self.trace_position[i] is not None:
12272
+ n_traces = len(self.trace_position[i])
12273
+ total_traces += n_traces
12274
+ else:
12275
+ n_traces = 0
12276
+
12277
+ if i >= 0 and i < len(self.n_sample) and self.n_sample[i] is not None:
12278
+ n_samples = self.n_sample[i]
12279
+ total_samples += n_samples * (len(self.trace_position[i]) if self.trace_position[i] else 0)
12280
+ else:
12281
+ n_samples = 0
12282
+
12283
+ # Track configuration
12284
+ config = (n_traces, n_samples)
12285
+ config_counts[config] = config_counts.get(config, 0) + 1
12286
+
12122
12287
  # Show import summary
12123
12288
  if failed_imports:
12124
- error_msg = f"Successfully imported {successful_imports} archive(s).\n\nFailed imports ({len(failed_imports)}):\n"
12289
+ error_msg = f"Successfully imported {successful_imports} archive(s).\n\n"
12290
+
12291
+ # Show configuration breakdown
12292
+ if len(config_counts) > 0:
12293
+ for (n_traces, n_samples), count in sorted(config_counts.items()):
12294
+ error_msg += f"• {count} archive(s): {n_traces} traces × {n_samples} samples\n"
12295
+
12296
+ error_msg += "\n"
12297
+ error_msg += f"Failed imports ({len(failed_imports)}):\n"
12125
12298
  for fname, error in failed_imports[:5]: # Show first 5 errors
12126
12299
  error_msg += f"\n• {fname}: {error}"
12127
12300
  if len(failed_imports) > 5:
12128
12301
  error_msg += f"\n\n... and {len(failed_imports) - 5} more"
12129
12302
  QMessageBox.warning(self, "Import Complete with Errors", error_msg)
12130
12303
  elif successful_imports > 0:
12131
- QMessageBox.information(
12132
- self, "Import Successful",
12133
- f"Successfully imported {successful_imports} ASCII archive(s)"
12134
- )
12304
+ if len(archive_paths) > 1:
12305
+ # Batch import summary
12306
+ summary_msg = f"Successfully imported {successful_imports} ASCII archive(s)\n\n"
12307
+
12308
+ # Show configuration breakdown
12309
+ if len(config_counts) > 0:
12310
+ for (n_traces, n_samples), count in sorted(config_counts.items()):
12311
+ summary_msg += f"• {count} archive(s): {n_traces} traces × {n_samples} samples\n"
12312
+
12313
+ QMessageBox.information(self, "Import Successful", summary_msg.rstrip())
12314
+ else:
12315
+ # Single archive - detailed info
12316
+ idx = len(self.streams) - 1
12317
+ n_traces = len(self.trace_position[idx]) if idx < len(self.trace_position) and self.trace_position[idx] else 0
12318
+ n_samp = self.n_sample[idx] if idx < len(self.n_sample) and self.n_sample[idx] else 0
12319
+ QMessageBox.information(
12320
+ self, "Import Successful",
12321
+ f"Imported {os.path.basename(archive_paths[0])}\n\n"
12322
+ f"Traces: {n_traces}\n"
12323
+ f"Samples per trace: {n_samp}"
12324
+ )
12135
12325
 
12136
12326
  #######################################
12137
12327
  # File loading and processing functions
@@ -12461,9 +12651,6 @@ class MainWindow(QMainWindow):
12461
12651
  # Close progress dialog
12462
12652
  progress.setValue(len(fileNames_new))
12463
12653
 
12464
- # Success - dialogs removed for smoother workflow
12465
- # Files are now visible in the file list
12466
-
12467
12654
  self.sortFiles() # Sort the files based on the file names
12468
12655
  self.updateFileListDisplay() # Update the file list display
12469
12656
  self.sortFileList() # Sort the file list widget
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyckster
3
- Version: 26.2.2
3
+ Version: 26.2.3
4
4
  Summary: A PyQt5-based GUI for the processing and analysis of active near-surface seismic data
5
5
  Home-page: https://gitlab.in2p3.fr/metis-geophysics/pyckster
6
6
  Author: Sylvain Pasquet
@@ -1,8 +1,8 @@
1
- pyckster/__init__.py,sha256=LO70RUeDFgSj8VdFhawOny6CVOPFksmbZ18sxkVpTBg,905
1
+ pyckster/__init__.py,sha256=qESM7e1M2mtkZ_qclsH4wVv39yjHCQrkPg1gO0xze7E,905
2
2
  pyckster/__main__.py,sha256=zv3AGVKorKo2tgWOEIcVnkDbp15eepSqka3IoWH_adU,406
3
3
  pyckster/auto_picking.py,sha256=fyZiOj0Ib-SB_oxsKnUszECHbOjo4JE23JVQILGYZco,12754
4
4
  pyckster/bayesian_inversion.py,sha256=kdnKOlAZ0JlYLipuFDHlwS7dU8LtI-0aMb90bYpEHhE,163523
5
- pyckster/core.py,sha256=0D3vDbpaToJ-RuNvpL7C4uGPLlrQaPvxb2xBuOTFxsI,1240456
5
+ pyckster/core.py,sha256=fcrnR7L18Gwc5AiXj5aWpdqRnjPDZbyWOFSyg0FIsa8,1250792
6
6
  pyckster/dispersion_stack_viewer.py,sha256=7Dh2e1tSct062D7Qh6nNrMdJcqKWcJvDIv84V8sC6C8,12645
7
7
  pyckster/inversion_app.py,sha256=ovM44oYBFsvfKxO7rjjThUhkJnLDLZZ0R6ZVp-5r66E,60676
8
8
  pyckster/inversion_manager.py,sha256=P8i1fqUJKMWkd-9PoDmNtmQuKglGKTeSuptUUA57D-8,15393
@@ -17,9 +17,9 @@ pyckster/surface_wave_profiling.py,sha256=L9KidhKmfGvVoPZjf6us3c49VB7VPB_VcsDqRx
17
17
  pyckster/sw_utils.py,sha256=-2CpQ9BkmUHaMBrNy2qXx1R-g9qPX8D9igKi_G-iRHE,13213
18
18
  pyckster/tab_factory.py,sha256=NlCIC6F8BrEu7a8BYOJJdWy5ftpX_zKDLj7SbcwBbh8,14519
19
19
  pyckster/visualization_utils.py,sha256=bgODn21NAQx1FOMPj91kdDd0szKOgUyfZ3cQlyu2PF8,47947
20
- pyckster-26.2.2.dist-info/licenses/LICENCE,sha256=-uaAIm20JrJKoMdCdn2GlFQfNU4fbsHWK3eh4kIQ_Ec,35143
21
- pyckster-26.2.2.dist-info/METADATA,sha256=mxaCepOXltujMuxOYLLnG-n4nehgEGZDfd38G8h-O8c,4567
22
- pyckster-26.2.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
23
- pyckster-26.2.2.dist-info/entry_points.txt,sha256=yrOQx1wHi84rbxX_ZYtYaVcK3EeuRhHRQDZRc8mB0NI,100
24
- pyckster-26.2.2.dist-info/top_level.txt,sha256=eaihhwhEmlysgdZE4HmELFdSUwlXcMv90YorkjOXujQ,9
25
- pyckster-26.2.2.dist-info/RECORD,,
20
+ pyckster-26.2.3.dist-info/licenses/LICENCE,sha256=-uaAIm20JrJKoMdCdn2GlFQfNU4fbsHWK3eh4kIQ_Ec,35143
21
+ pyckster-26.2.3.dist-info/METADATA,sha256=lUsnI0wr-TluggRLaC0MF5rUyFfm-VMhZ0H0YK5uZk0,4567
22
+ pyckster-26.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
23
+ pyckster-26.2.3.dist-info/entry_points.txt,sha256=yrOQx1wHi84rbxX_ZYtYaVcK3EeuRhHRQDZRc8mB0NI,100
24
+ pyckster-26.2.3.dist-info/top_level.txt,sha256=eaihhwhEmlysgdZE4HmELFdSUwlXcMv90YorkjOXujQ,9
25
+ pyckster-26.2.3.dist-info/RECORD,,