pyseiskit 0.1.0__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.
Files changed (41) hide show
  1. pyseiskit-0.1.0/.gitignore +34 -0
  2. pyseiskit-0.1.0/LICENSE +21 -0
  3. pyseiskit-0.1.0/PKG-INFO +43 -0
  4. pyseiskit-0.1.0/README.md +18 -0
  5. pyseiskit-0.1.0/demos/gain.ipynb +169 -0
  6. pyseiskit-0.1.0/demos/seismic_reader.py +76 -0
  7. pyseiskit-0.1.0/demos/wiggle.ipynb +209 -0
  8. pyseiskit-0.1.0/legacy/boto/BaseVisualization.py +104 -0
  9. pyseiskit-0.1.0/legacy/boto/WiggleDisplay.py +92 -0
  10. pyseiskit-0.1.0/legacy/boto/sufile.py +36 -0
  11. pyseiskit-0.1.0/legacy/boto/transforms.py +153 -0
  12. pyseiskit-0.1.0/legacy/display.sh +50 -0
  13. pyseiskit-0.1.0/legacy/landwave/DatasetFile.py +221 -0
  14. pyseiskit-0.1.0/legacy/landwave/wigglePatchesRenderFactory.py +128 -0
  15. pyseiskit-0.1.0/pyproject.toml +51 -0
  16. pyseiskit-0.1.0/pyseiskit/__init__.py +7 -0
  17. pyseiskit-0.1.0/pyseiskit/modules/__init__.py +0 -0
  18. pyseiskit-0.1.0/pyseiskit/modules/applyGains/__init__.py +0 -0
  19. pyseiskit-0.1.0/pyseiskit/modules/applyGains/adapters/__init__.py +1 -0
  20. pyseiskit-0.1.0/pyseiskit/modules/applyGains/adapters/clipAdapter.py +16 -0
  21. pyseiskit-0.1.0/pyseiskit/modules/applyGains/applyGains.py +42 -0
  22. pyseiskit-0.1.0/pyseiskit/modules/applyGains/gainStrategies.py +11 -0
  23. pyseiskit-0.1.0/pyseiskit/modules/clip/__init__.py +1 -0
  24. pyseiskit-0.1.0/pyseiskit/modules/clip/contracts/PercentileClip.py +19 -0
  25. pyseiskit-0.1.0/pyseiskit/modules/clip/contracts/__init__.py +1 -0
  26. pyseiskit-0.1.0/pyseiskit/modules/clip/percentileClip.py +31 -0
  27. pyseiskit-0.1.0/pyseiskit/modules/gain/__init__.py +2 -0
  28. pyseiskit-0.1.0/pyseiskit/modules/gain/agc.py +52 -0
  29. pyseiskit-0.1.0/pyseiskit/modules/gain/contracts/AutomaticGain.py +21 -0
  30. pyseiskit-0.1.0/pyseiskit/modules/gain/contracts/GenericGain.py +19 -0
  31. pyseiskit-0.1.0/pyseiskit/modules/gain/contracts/__init__.py +2 -0
  32. pyseiskit-0.1.0/pyseiskit/modules/gain/gagc.py +57 -0
  33. pyseiskit-0.1.0/pyseiskit/modules/palettes/PALETTES.py +12 -0
  34. pyseiskit-0.1.0/pyseiskit/modules/palettes/__init__.py +1 -0
  35. pyseiskit-0.1.0/pyseiskit/modules/palettes/getFadingPalette.py +19 -0
  36. pyseiskit-0.1.0/pyseiskit/modules/sourceData/__init__.py +3 -0
  37. pyseiskit-0.1.0/pyseiskit/modules/sourceData/rescaleDataForWiggle.py +52 -0
  38. pyseiskit-0.1.0/pyseiskit/modules/sourceData/wiggleLinesDataFactory.py +19 -0
  39. pyseiskit-0.1.0/pyseiskit/modules/sourceData/wigglePatchesDataFactory.py +126 -0
  40. pyseiskit-0.1.0/pyseiskit/py.typed +0 -0
  41. pyseiskit-0.1.0/uv.lock +556 -0
@@ -0,0 +1,34 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ share/python-wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ # Virtual environments
25
+ venv/
26
+ env/
27
+ ENV/
28
+ env.bak/
29
+ venv.bak/
30
+
31
+ # mock data
32
+ *.su
33
+ *.segy
34
+ *.sgy
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PETROGEO
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyseiskit
3
+ Version: 0.1.0
4
+ Summary: A Python library for seismic data processing and pre-visualization.
5
+ Project-URL: Homepage, https://github.com/PETROGEO-UFRN/pyseiskit
6
+ Project-URL: Repository, https://github.com/PETROGEO-UFRN/pyseiskit
7
+ Author-email: JorbFreire <jorbfreire@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: SU,data processing,geophysics,seismic,seismic unix,wiggle
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: numpy
23
+ Requires-Dist: scipy
24
+ Description-Content-Type: text/markdown
25
+
26
+ # pyseiskit
27
+
28
+ A Python library for seismic data processing.
29
+
30
+ Includes *wiggle* helpers, wich can be used together with common plot libraries such as:
31
+
32
+ - Matplotlib
33
+ - Bokeh
34
+ - Plotly
35
+
36
+ ## Installation
37
+ ```bash
38
+ pip install pyseiskit
39
+ ```
40
+
41
+ ## [Available Demos](/demos)
42
+ - [Wiggle plotting with common libraries](/demos/wiggle.ipynb)
43
+ - [Gain methods](/demos/gain.ipynb)
@@ -0,0 +1,18 @@
1
+ # pyseiskit
2
+
3
+ A Python library for seismic data processing.
4
+
5
+ Includes *wiggle* helpers, wich can be used together with common plot libraries such as:
6
+
7
+ - Matplotlib
8
+ - Bokeh
9
+ - Plotly
10
+
11
+ ## Installation
12
+ ```bash
13
+ pip install pyseiskit
14
+ ```
15
+
16
+ ## [Available Demos](/demos)
17
+ - [Wiggle plotting with common libraries](/demos/wiggle.ipynb)
18
+ - [Gain methods](/demos/gain.ipynb)
@@ -0,0 +1,169 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# PySeis Gain & AGC Demo\n",
8
+ "This notebook demonstrates how to replicate Seismic Unix processing pipelines (like `sugain` and `suxwigb` clipping) using PySeis."
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "metadata": {},
15
+ "outputs": [],
16
+ "source": [
17
+ "%pip install bokeh segyio"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": null,
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "# Install pyseiskit from PyPI\n",
27
+ "%pip install pyseiskit\n",
28
+ "# Install for local development\n",
29
+ "# %pip install -e .."
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "markdown",
34
+ "metadata": {},
35
+ "source": [
36
+ "## 1A. Option 1: Create Simple Synthetic Data\n",
37
+ "Run this cell to generate a small 2D array representing 5 seismic traces, each with 100 time samples."
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "import numpy as np\n",
47
+ "\n",
48
+ "# 100 samples, 5 traces\n",
49
+ "data = np.random.randn(100, 5) \n",
50
+ "times = np.arange(100)\n",
51
+ "offsets = np.arange(5, dtype=float)\n"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "markdown",
56
+ "metadata": {},
57
+ "source": [
58
+ "## 1B. Option 2: Load Real `.su` or `.sgy` Data\n",
59
+ "Run this cell instead if you have the file `tac-204RL239.su` in the same folder as this notebook."
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "code",
64
+ "execution_count": null,
65
+ "metadata": {},
66
+ "outputs": [],
67
+ "source": [
68
+ "import segyio\n",
69
+ "from seismic_reader import read_seismic_file\n",
70
+ "\n",
71
+ "filename = 'tac-204RL239.su'\n",
72
+ "\n",
73
+ "# We only want to plot a single gather to avoid rendering thousands of traces.\n",
74
+ "# FieldRecord corresponds to the 'fldr' header in SU/SEGY.\n",
75
+ "gather_key = segyio.TraceField.FieldRecord\n",
76
+ "gather_index = 50 # Change this to a valid fldr number from your dataset!\n",
77
+ "\n",
78
+ "try:\n",
79
+ " data, offsets, times = read_seismic_file(filename, gather_key=gather_key, gather_index=gather_index)\n",
80
+ " print(f\"Loaded {data.shape[1]} traces for fldr {gather_index} with {data.shape[0]} samples each.\")\n",
81
+ "except FileNotFoundError:\n",
82
+ " print(f\"File '{filename}' not found. Please place it in the 'demos' folder or stick to Option 1A.\")\n",
83
+ "except ValueError as e:\n",
84
+ " print(f\"Error: {e}\")"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "markdown",
89
+ "metadata": {},
90
+ "source": [
91
+ "## 2. Process Data for Wiggles\n",
92
+ "Regardless of how you loaded the data above, we now pass it through PySeis."
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "metadata": {},
99
+ "outputs": [],
100
+ "source": [
101
+ "from pyseiskit import sourceData\n",
102
+ "from pyseiskit import gain\n",
103
+ "from pyseiskit import clip\n",
104
+ "\n",
105
+ "# Replicating SU pipeline: suwind | sugain agc=1 wagc=1.0 | suxwigb perc=99\n",
106
+ "dt = times[1] - times[0]\n",
107
+ "\n",
108
+ "# 1. Apply AGC (Optional, just like sugain agc=1 wagc=1.0)\n",
109
+ "data_gained = gain.applyAGC(data, wagc=1.0, intervalTimeSamples=dt)\n",
110
+ "# data_gained = data # uncomment above to apply AGC\n",
111
+ "\n",
112
+ "# 2. Apply Percentile Clipping (Like suxwigb perc=99 flat-topping)\n",
113
+ "data_clipped = clip.applyPercentileClip(data_gained, percentile=99.0)\n",
114
+ "\n",
115
+ "# 3. Scale physical dimensions (overlap=1.0 is SU default xcur/overlap)\n",
116
+ "scaled_data = sourceData.rescaleDataForWiggle(data_clipped, offsets, overlap=1.0)\n",
117
+ "\n",
118
+ "# 4. Generate geometry\n",
119
+ "line_data = sourceData.wiggleLinesDataFactory(scaled_data, offsets, times)\n",
120
+ "patch_data = sourceData.wigglePatchesDataFactory(scaled_data, offsets, times, fill_mode='positive')"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "markdown",
125
+ "metadata": {},
126
+ "source": [
127
+ "## 3. Visualize Results\n",
128
+ "Here we use Bokeh to visualize the gained results interactively."
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "from bokeh.plotting import figure, show, output_notebook\n",
138
+ "output_notebook()\n",
139
+ "\n",
140
+ "bokeh_plot = figure(width=600, height=400, y_range=(times[-1], times[0]))\n",
141
+ "bokeh_plot.multi_line(**line_data, color='black', line_width=0.5)\n",
142
+ "bokeh_plot.patches(**patch_data, color='black', line_width=0)\n",
143
+ "\n",
144
+ "show(bokeh_plot)"
145
+ ]
146
+ }
147
+ ],
148
+ "metadata": {
149
+ "kernelspec": {
150
+ "display_name": "pyseis (3.12.2)",
151
+ "language": "python",
152
+ "name": "python3"
153
+ },
154
+ "language_info": {
155
+ "codemirror_mode": {
156
+ "name": "ipython",
157
+ "version": 3
158
+ },
159
+ "file_extension": ".py",
160
+ "mimetype": "text/x-python",
161
+ "name": "python",
162
+ "nbconvert_exporter": "python",
163
+ "pygments_lexer": "ipython3",
164
+ "version": "3.12.2"
165
+ }
166
+ },
167
+ "nbformat": 4,
168
+ "nbformat_minor": 4
169
+ }
@@ -0,0 +1,76 @@
1
+ import numpy as np
2
+ import segyio
3
+ from pathlib import Path
4
+
5
+ def read_seismic_file(filepath, gather_key=None, gather_index=None):
6
+ """
7
+ Reads a .su or .sgy file and returns the data, times, and offsets.
8
+ If gather_key and gather_index are provided, it only loads traces
9
+ matching that specific gather (e.g. a specific fldr or cdp).
10
+ """
11
+ path = Path(filepath)
12
+ if not path.is_file():
13
+ raise FileNotFoundError(f"File not found: {path}")
14
+
15
+ is_su = path.suffix.lower() == '.su'
16
+
17
+ # Open the file depending on its extension
18
+ if is_su:
19
+ dataset = segyio.su.open(str(path), "r", ignore_geometry=True, endian='little')
20
+ else:
21
+ dataset = segyio.open(str(path), "r", ignore_geometry=True)
22
+
23
+ try:
24
+ if gather_key is not None and gather_index is not None:
25
+ # Group traces by their gather key (e.g. all traces sharing the same fldr)
26
+ key_to_trace_indices = {}
27
+ for i in range(dataset.tracecount):
28
+ val = int(dataset.header[i][gather_key])
29
+ if val not in key_to_trace_indices:
30
+ key_to_trace_indices[val] = []
31
+ key_to_trace_indices[val].append(i)
32
+
33
+ available_gathers = sorted(key_to_trace_indices.keys())
34
+ if not available_gathers:
35
+ raise ValueError(f"No valid values found for header key {gather_key}")
36
+
37
+ # Safely select the requested gather index
38
+ safe_index = max(0, min(gather_index, len(available_gathers) - 1))
39
+ selected_gather_val = available_gathers[safe_index]
40
+ trace_indices = key_to_trace_indices[selected_gather_val]
41
+
42
+ print(f"Selected gather {safe_index} (Header value: {selected_gather_val}) containing {len(trace_indices)} traces.")
43
+
44
+ raw_traces = np.stack([dataset.trace[i] for i in trace_indices])
45
+
46
+ offsets = np.array([
47
+ dataset.header[i][segyio.TraceField.offset]
48
+ for i in trace_indices
49
+ ], dtype=float)
50
+
51
+ # If the offset header is missing or all zero, fallback to trace indices
52
+ if len(offsets) > 1 and np.all(offsets == offsets[0]):
53
+ print("Warning: Trace offsets are all identical (likely missing header). Falling back to trace indices.")
54
+ offsets = np.arange(len(trace_indices), dtype=float)
55
+ else:
56
+ # Load all traces into memory
57
+ raw_traces = dataset.trace.raw[:]
58
+ offsets = np.arange(raw_traces.shape[0], dtype=float)
59
+
60
+ # We transpose so that data is (samples x traces) for wiggle plotting
61
+ data = raw_traces.T
62
+
63
+ # Calculate times based on sample interval
64
+ if is_su:
65
+ dt_micros = dataset.header[0][segyio.TraceField.TRACE_SAMPLE_INTERVAL]
66
+ else:
67
+ dt_micros = dataset.bin[segyio.BinField.Interval]
68
+
69
+ dt_seconds = dt_micros / 1e6
70
+ num_samples = len(dataset.samples)
71
+ times = np.arange(num_samples) * dt_seconds
72
+
73
+ return data, offsets, times
74
+
75
+ finally:
76
+ dataset.close()
@@ -0,0 +1,209 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# PySeis Wiggle Plots Demo\n",
8
+ "This notebook demonstrates how to plot wiggle traces using PySeis with Matplotlib, Bokeh, and Plotly."
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "metadata": {},
15
+ "outputs": [],
16
+ "source": [
17
+ "%pip install matplotlib bokeh plotly segyio"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": null,
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "# Install pyseiskit from PyPI\n",
27
+ "%pip install pyseiskit\n",
28
+ "# Install for local development\n",
29
+ "# %pip install -e .."
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "markdown",
34
+ "metadata": {},
35
+ "source": [
36
+ "## 1A. Option 1: Create Simple Synthetic Data\n",
37
+ "Run this cell to generate a small 2D array representing 5 seismic traces, each with 100 time samples."
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "import numpy as np\n",
47
+ "\n",
48
+ "# 100 samples, 5 traces\n",
49
+ "data = np.random.randn(100, 5) \n",
50
+ "times = np.arange(100)\n",
51
+ "offsets = np.arange(5, dtype=float)\n"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "markdown",
56
+ "metadata": {},
57
+ "source": [
58
+ "## 1B. Option 2: Load Real `.su` or `.sgy` Data\n",
59
+ "Run this cell instead if you have the file `tac-204RL239.su` in the same folder as this notebook."
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "code",
64
+ "execution_count": null,
65
+ "metadata": {},
66
+ "outputs": [],
67
+ "source": [
68
+ "import segyio\n",
69
+ "from seismic_reader import read_seismic_file\n",
70
+ "\n",
71
+ "filename = 'tac-204RL239.su'\n",
72
+ "\n",
73
+ "# We only want to plot a single gather to avoid rendering thousands of traces.\n",
74
+ "# FieldRecord corresponds to the 'fldr' header in SU/SEGY.\n",
75
+ "gather_key = segyio.TraceField.FieldRecord\n",
76
+ "gather_index = 50 # Change this to a valid fldr number from your dataset!\n",
77
+ "\n",
78
+ "try:\n",
79
+ " data, offsets, times = read_seismic_file(filename, gather_key=gather_key, gather_index=gather_index)\n",
80
+ " print(f\"Loaded {data.shape[1]} traces for fldr {gather_index} with {data.shape[0]} samples each.\")\n",
81
+ "except FileNotFoundError:\n",
82
+ " print(f\"File '{filename}' not found. Please place it in the 'demos' folder or stick to Option 1A.\")\n",
83
+ "except ValueError as e:\n",
84
+ " print(f\"Error: {e}\")"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "markdown",
89
+ "metadata": {},
90
+ "source": [
91
+ "## 2. Process Data for Wiggles\n",
92
+ "Regardless of how you loaded the data above, we now pass it through PySeis."
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "metadata": {},
99
+ "outputs": [],
100
+ "source": [
101
+ "from pyseiskit import sourceData\n",
102
+ "\n",
103
+ "scaled_data = sourceData.rescaleDataForWiggle(data, offsets, overlap=1.0)\n",
104
+ "line_data = sourceData.wiggleLinesDataFactory(scaled_data, offsets, times)\n",
105
+ "patch_data = sourceData.wigglePatchesDataFactory(scaled_data, offsets, times, fill_mode='positive')"
106
+ ]
107
+ },
108
+ {
109
+ "cell_type": "markdown",
110
+ "metadata": {},
111
+ "source": [
112
+ "## 3. Plotting with Matplotlib"
113
+ ]
114
+ },
115
+ {
116
+ "cell_type": "code",
117
+ "execution_count": null,
118
+ "metadata": {},
119
+ "outputs": [],
120
+ "source": [
121
+ "import matplotlib.pyplot as plt\n",
122
+ "\n",
123
+ "matplotlib_figure, matplotlib_axes = plt.subplots(figsize=(6, 4))\n",
124
+ "\n",
125
+ "# Plot filled areas\n",
126
+ "for x, y in zip(patch_data['xs'], patch_data['ys']):\n",
127
+ " matplotlib_axes.fill(x, y, color='black')\n",
128
+ "\n",
129
+ "# Plot trace lines\n",
130
+ "for x, y in zip(line_data['xs'], line_data['ys']):\n",
131
+ " matplotlib_axes.plot(x, y, color='black', linewidth=0.5)\n",
132
+ "\n",
133
+ "matplotlib_axes.invert_yaxis() # Time goes down\n",
134
+ "plt.show()"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "markdown",
139
+ "metadata": {},
140
+ "source": [
141
+ "## 4. Plotting with Bokeh"
142
+ ]
143
+ },
144
+ {
145
+ "cell_type": "code",
146
+ "execution_count": null,
147
+ "metadata": {},
148
+ "outputs": [],
149
+ "source": [
150
+ "from bokeh.plotting import figure, show, output_notebook\n",
151
+ "output_notebook()\n",
152
+ "\n",
153
+ "bokeh_plot = figure(width=600, height=400, y_range=(times[-1], times[0]))\n",
154
+ "bokeh_plot.multi_line(**line_data, color='black', line_width=0.5)\n",
155
+ "bokeh_plot.patches(**patch_data, color='black', line_width=0)\n",
156
+ "\n",
157
+ "show(bokeh_plot)"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "markdown",
162
+ "metadata": {},
163
+ "source": [
164
+ "## 5. Plotting with Plotly"
165
+ ]
166
+ },
167
+ {
168
+ "cell_type": "code",
169
+ "execution_count": null,
170
+ "metadata": {},
171
+ "outputs": [],
172
+ "source": [
173
+ "import plotly.graph_objects as go\n",
174
+ "\n",
175
+ "plotly_figure = go.Figure()\n",
176
+ "\n",
177
+ "for x, y in zip(line_data['xs'], line_data['ys']):\n",
178
+ " plotly_figure.add_trace(go.Scatter(x=x, y=y, mode='lines', line=dict(color='black', width=0.5), showlegend=False))\n",
179
+ "\n",
180
+ "for x, y in zip(patch_data['xs'], patch_data['ys']):\n",
181
+ " plotly_figure.add_trace(go.Scatter(x=x, y=y, fill='toself', fillcolor='black', line=dict(width=0), showlegend=False))\n",
182
+ "\n",
183
+ "plotly_figure.update_layout(yaxis=dict(autorange='reversed'), height=500)\n",
184
+ "plotly_figure.show()"
185
+ ]
186
+ }
187
+ ],
188
+ "metadata": {
189
+ "kernelspec": {
190
+ "display_name": "pyseis (3.12.2)",
191
+ "language": "python",
192
+ "name": "python3"
193
+ },
194
+ "language_info": {
195
+ "codemirror_mode": {
196
+ "name": "ipython",
197
+ "version": 3
198
+ },
199
+ "file_extension": ".py",
200
+ "mimetype": "text/x-python",
201
+ "name": "python",
202
+ "nbconvert_exporter": "python",
203
+ "pygments_lexer": "ipython3",
204
+ "version": "3.12.2"
205
+ }
206
+ },
207
+ "nbformat": 4,
208
+ "nbformat_minor": 4
209
+ }
@@ -0,0 +1,104 @@
1
+ import numpy as np
2
+ import numpy.typing as np_types
3
+ from seismicio.Models.SuDataModel import SuFile
4
+
5
+ from ...constants.VISUALIZATION import FIRST_TIME_SAMPLE
6
+ from ...services.sufile import get_stack_sufile, get_multi_gather_sufile
7
+ from .BasePlotOptionsState import BasePlotOptionsState
8
+
9
+ def debug(message: str):
10
+ print(f"DEBUG: {message}", flush=True)
11
+
12
+
13
+ class BaseVisualization:
14
+ sufile: SuFile
15
+ plot_options_state: BasePlotOptionsState
16
+ gather_offsets: np_types.NDArray | None
17
+
18
+ def __init__(
19
+ self,
20
+ filename: str,
21
+ plot_options_state: BasePlotOptionsState,
22
+ gather_key: str | None = None,
23
+ ) -> None:
24
+ self.plot_options_state = plot_options_state
25
+ if gather_key:
26
+ self.sufile: SuFile = get_multi_gather_sufile(
27
+ plot_options=self.plot_options_state.__dict__,
28
+ filename=filename,
29
+ gather_key=gather_key,
30
+ )
31
+ else:
32
+ self.sufile = get_stack_sufile(
33
+ plot_options=self.plot_options_state.__dict__,
34
+ filename=filename,
35
+ )
36
+
37
+ def getShotGathersData(
38
+ self,
39
+ index_start: int | None = None
40
+ ):
41
+ if index_start is None:
42
+ index_start = self.plot_options_state.gather_index_start
43
+ index_stop = index_start + self.plot_options_state.num_loadedgathers
44
+ # ! igather VS gather
45
+ selected_gathers = self.sufile.igather[
46
+ index_start:index_stop
47
+ ]
48
+
49
+ last_time_sample = \
50
+ FIRST_TIME_SAMPLE + \
51
+ (self.plot_options_state.num_time_samples - 1) * \
52
+ self.plot_options_state.interval_time_samples
53
+
54
+ width_time_samples = np.abs(
55
+ last_time_sample - FIRST_TIME_SAMPLE
56
+ )
57
+ self.plot_options_state.updatePlotOptionsState(
58
+ width_time_samples=width_time_samples,
59
+ )
60
+
61
+ if (index_stop - 1 == index_start):
62
+ # *** Single gather
63
+ self.gather_offsets = selected_gathers.headers["offset"]
64
+ else:
65
+ # *** Multiple gathers
66
+ self.gather_offsets = None
67
+
68
+ # --- DEBUG LOGS START ---
69
+ debug(f"DEBUG: index_start = {index_start}, index_stop = {index_stop}")
70
+ debug(f"DEBUG: num_loadedgathers = {self.plot_options_state.num_loadedgathers}")
71
+ debug(f"DEBUG: Data type (dtype) = {selected_gathers.data.dtype}")
72
+ debug(f"DEBUG: Data shape = {selected_gathers.data.shape}")
73
+
74
+ # Check for non-standard values that might break VTK color mapping
75
+ debug(f"DEBUG: Contains NaNs? = {np.isnan(selected_gathers.data).any()}")
76
+ debug(f"DEBUG: Min Amplitude = {np.nanmin(selected_gathers.data)}")
77
+ debug(f"DEBUG: Max Amplitude = {np.nanmax(selected_gathers.data)}")
78
+
79
+ if self.gather_offsets is not None:
80
+ debug(f"DEBUG: gather_offsets shape = {self.gather_offsets.shape}")
81
+ # --- DEBUG LOGS END ---
82
+ return selected_gathers.data
83
+
84
+ def getBaseData(self) -> np_types.NDArray:
85
+ """
86
+ Get Numpy NDArray for data section on display
87
+
88
+ Handles stack or sectioned data (shot gathers)
89
+ """
90
+ # *** "gather_keyword" must exist for shot gathers
91
+ if self.sufile.gather_keyword:
92
+ data = self.getShotGathersData()
93
+ else:
94
+ data = self.sufile.traces
95
+ self.gather_offsets = None
96
+ return data
97
+
98
+ def handle_state_change(self):
99
+ raise NotImplementedError(
100
+ """
101
+ Missing custom handle_state_change() for this Visualization
102
+ handle_state_change() method must be re-implmented when extending BaseVisualization
103
+ """
104
+ )