<jupyter_start><jupyter_text>Write SEG-Y with `obspy`Before going any further, you might like to know, [What is SEG-Y?](http://www.agilegeoscience.com/blog/2014/3/26/what-is-seg-y.html). See also the articles in [SubSurfWiki](http://www.subsurfwiki.org/wiki/SEG_Y) and [Wikipedia](https://en.wikipedia.org/wiki/SEG_Y).We'll use the [obspy](https://github.com/obspy/obspy) seismology library to read and write SEGY data.    Technical SEG-Y documentation:* [SEG-Y Rev 1](http://seg.org/Portals/0/SEG/News%20and%20Resources/Technical%20Standards/seg_y_rev1.pdf)* [SEG-Y Rev 2 proposal](https://www.dropbox.com/s/txrqsfuwo59fjea/SEG-Y%20Rev%202.0%20Draft%20August%202015.pdf?dl=0) and [draft repo](http://community.seg.org/web/technical-standards-committee/documents/-/document_library/view/6062543)<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
ls -l ../data/*.sgy<jupyter_output><empty_output><jupyter_text>2D data<jupyter_code>filename = '../data/HUN00-ALT-01_STK.sgy'
from obspy.io.segy.segy import _read_segy
section = _read_segy(filename)  # unpack_headers=True slows you down here
data = np.vstack([t.data for t in section.traces])
plt.figure(figsize=(16,8))
plt.imshow(data.T, cmap="Greys")
plt.colorbar(shrink=0.5)
plt.show()<jupyter_output><empty_output><jupyter_text>Formatted header:<jupyter_code>def chunk(string, width=80):
    lines = int(np.ceil(len(string) / width))
    result = ''
    for i in range(lines):
        line = string[i*width:i*width+width]
        result += line + (width-len(line))*' ' + '\n'
    return result

s = section.textual_file_header.decode()
print(chunk(s))
section.binary_file_header
section.traces[0].header
len(section.traces[0].data)<jupyter_output><empty_output><jupyter_text>Change the dataLet's scale the data.<jupyter_code>scaled = data / 1000
scaled[np.isnan(scaled)] = 0
scaled
vm = np.percentile(scaled, 99)

plt.figure(figsize=(16,8))
plt.imshow(scaled.T, cmap="Greys", vmin=-vm, vmax=vm)
plt.colorbar(shrink=0.5)
plt.show()<jupyter_output><empty_output><jupyter_text>Write dataLet's write this all back to a new SEG-Y file.<jupyter_code>from obspy.core import Trace, Stream, UTCDateTime
from obspy.io.segy.segy import SEGYTraceHeader
stream = Stream()

for i, trace in enumerate(scaled):

    # Make the trace.
    tr = Trace(trace)

    # Add required data.
    tr.stats.delta = 0.004
    tr.stats.starttime = 0  # Not strictly required.

    # Add yet more to the header (optional).
    tr.stats.segy = {'trace_header': SEGYTraceHeader()}
    tr.stats.segy.trace_header.trace_sequence_number_within_line = i + 1
    tr.stats.segy.trace_header.receiver_group_elevation = 0

    # Append the trace to the stream.
    stream.append(tr)
stream
stream.write('../data/out.sgy', format='SEGY', data_encoding=5)  # encode 5 for IEEE<jupyter_output><empty_output><jupyter_text>Add a file-wide headerSo far we only attached metadata to the traces, but we can do more by attaching some filewide metadata, like a textual header. A SEGY file normally has a file wide text header. This can be attached to the stream object.If this header and the binary header are not set, they will be autocreated with defaults.<jupyter_code>from obspy.core import AttribDict
from obspy.io.segy.segy import SEGYBinaryFileHeader
# Text header.
stream.stats = AttribDict()
stream.stats.textual_file_header = '{:80s}'.format('This is the textual header.').encode()
stream.stats.textual_file_header += '{:80s}'.format('This file contains seismic data.').encode()

# Binary header.
stream.stats.binary_file_header = SEGYBinaryFileHeader()
stream.stats.binary_file_header.trace_sorting_code = 4
stream.stats.binary_file_header.seg_y_format_revision_number = 0x0100
import sys
stream.write('../data/out.sgy', format='SEGY', data_encoding=5, byteorder=sys.byteorder)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13142857142857142, 'fraction_numerical': 0.023116883116883116, 'mean_word_length': 5.271986970684039, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 3, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '18069', 'license': 'Apache-2.0', 'n_tokens_mistral': 1474, 'n_tokens_neox': 1376, 'n_words': 294, 'path': 'instructor/Write_SEGY_with_ObsPy.ipynb', 'repo_name': 'michael-scarn/geocomp-0118', 'size': '3850'}