Traces

Altay Sansal

Feb 12, 2026

5 min read

Defining a Trace

The TraceSpec is a way to define the structure of a seismic trace as stored in SEG-Y files. It is composed of Trace Header Specification and Trace Data Specification. This information is combined using the TraceSpec.

The TraceSpec has fields for trace header, optional extended trace header, and trace data definitions. We also provide an optional offset field to define the beginning byte-location of the traces within a binary file. Most of the time this field gets populated automatically.

A custom trace specification can be built programmatically following a simple workflow. The same spec can be built from JSON as well. Navigate to JSON Trace Specification below for that.

Trace Header Specification

Trace headers are defined using HeaderSpec. Each header field is a HeaderField. We have an example workflow here. You can see more examples in the Data Types documentation.

We first do the required imports and then define header fields. We don’t allow setting endianness for individual fields.

1
2from segy.schema import HeaderField
3
4trace_header_fields = [
5    HeaderField(name="inline", byte=189, format="int32"),
6    HeaderField(name="crossline", byte=193, format="int32"),
7]

Then we create HeaderSpec for trace headers. We know trace headers must be 240-bytes so we declare it. This will ensure we read/write with correct padding.

Note

Endianness can be set here but we don’t recommend it. By default it will take the machine endianness. When the SegyFile is initialized it will automatically set this to the correct value. By default its None.

1
2from segy.schema import HeaderSpec
3
4trace_header_spec = HeaderSpec(
5    fields=trace_header_fields,
6    item_size=240,
7)

Trace Data Specification

Trace data is described using TraceDataSpec. The data is mainly explained by its data format and number of samples.

Continuing our previous example, we build the trace data spec. We assume that samples are encoded in ibm32 format. Endianness can’t be set here, because it is assigned at TraceSpec level.

1
2from segy.schema import TraceDataSpec
3
4trace_data_spec = TraceDataSpec(
5    format="ibm32",
6    samples=360
7)

Trace Specification

Finally, since we have all components, we can create a trace specification.

1from segy.schema import TraceSpec
2
3trace_spec = TraceSpec(
4    header_spec=trace_header_spec,
5    data_spec=trace_data_spec,
6    offset=3600  # just an example of possible offset
7)

Note

Endianness can be set here but we don’t recommend it. By default it will take the machine endianness. When the SegyFile is initialized it will automatically set this to the correct value. By default its None.

If we look at the Numpy data type of the trace, we can see how it will be decoded from raw bytes:

1>>> trace_spec.dtype
2dtype([('header', {'names': ['inline', 'crossline'], 'formats': ['<i4', '<i4'], 'offsets': [188, 192], 'itemsize': 240}), ('data', '<u4', (360,))])

JSON Trace Specification

We can define the exact same trace specification above using JSON. This can either be defined as a string or can be read from a file. Both will work. Let’s write the JSON.

{
  "headerSpec": {
    "fields": [
      {
        "format": "int32",
        "name": "inline",
        "byte": 189
      },
      {
        "format": "int32",
        "name": "crossline",
        "byte": 193
      }
    ],
    "itemSize": 240
  },
  "dataSpec": {
    "format": "ibm32",
    "samples": 360
  },
  "offset": 3600
}

Then if we have our JSON as a string in the variable json_str, we can generate the same specification, with validation of all fields. If there are any errors in the JSON, there will be a validation error raised.

1>>> trace_spec_from_json = TraceSpec.model_validate_json(json_str)
2>>> trace_spec_from_json == trace_spec
3True

Reference

pydantic model segy.schema.TraceSpec

A spec class for a trace (header + data).

Show JSON schema
{
   "title": "TraceSpec",
   "description": "A spec class for a trace (header + data).",
   "type": "object",
   "properties": {
      "header": {
         "$ref": "#/$defs/HeaderSpec",
         "description": "Trace header spec."
      },
      "extHeader": {
         "anyOf": [
            {
               "$ref": "#/$defs/HeaderSpec"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Extended trace header spec."
      },
      "data": {
         "$ref": "#/$defs/TraceDataSpec",
         "description": "Trace data spec."
      },
      "offset": {
         "anyOf": [
            {
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Starting offset of the trace.",
         "title": "Offset"
      },
      "endianness": {
         "anyOf": [
            {
               "$ref": "#/$defs/Endianness"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Endianness of traces and headers."
      },
      "count": {
         "anyOf": [
            {
               "minimum": 0,
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Number of traces.",
         "title": "Count"
      }
   },
   "$defs": {
      "Endianness": {
         "description": "Enumeration class with three possible endianness values.\n\nAttributes:\n    BIG: Big endian.\n    LITTLE: Little endian.\n\nExamples:\n    >>> endian = Endianness.BIG\n    >>> print(endian.symbol)\n    >",
         "enum": [
            "big",
            "little"
         ],
         "title": "Endianness",
         "type": "string"
      },
      "HeaderField": {
         "description": "A class representing header field spec.\n\nExamples:\n    A named float starting at byte location 9:\n\n    >>> field = HeaderField(\n    >>>     name=\"my_var\",\n    >>>     format=\"float32\",\n    >>>     byte=9,\n    >>> )\n\n    The name, byte, and offset fields will only be used if the structured\n    field is used within the context of a :class:`HeaderSpec`. Offset is\n    calculated automatically from byte location.\n\n    >>> field.name\n    my_var\n    >>> field.byte\n    9\n    >>> field.offset\n    8\n\n    The `dtype` property is inherited from :class:`DataFormat`.\n\n    >>> field.dtype\n    dtype('float32')",
         "properties": {
            "name": {
               "description": "The short name of the field.",
               "title": "Name",
               "type": "string"
            },
            "byte": {
               "description": "Field's start byte location.",
               "minimum": 1,
               "title": "Byte",
               "type": "integer"
            },
            "format": {
               "$ref": "#/$defs/ScalarType",
               "description": "The data type of the field."
            }
         },
         "required": [
            "name",
            "byte",
            "format"
         ],
         "title": "HeaderField",
         "type": "object"
      },
      "HeaderSpec": {
         "description": "A class representing a header specification.\n\nExamples:\n    Let's build a header from scratch!\n\n    We will define three fields with different names, data-types, and\n    start byte locations.\n\n    >>> field1 = HeaderField(\n    >>>     name=\"foo\",\n    >>>     format=\"int32\",\n    >>>     byte=1,\n    >>> )\n    >>> field2 = HeaderField(\n    >>>     name=\"bar\",\n    >>>     format=\"int16\",\n    >>>     byte=5,\n    >>> )\n    >>> field3 = HeaderField(\n    >>>     name=\"fizz\",\n    >>>     format=\"int32\",\n    >>>     byte=17,\n    >>> )\n\n    Note that the fields span the following byte ranges:\n\n    * `field1` between bytes `[0, 4)`\n    * `field2` between bytes `[4, 6)`\n    * `field3` between bytes `[16, 20)`\n\n    The gap between `field2` and `field3` will be padded with `void`. In\n    this case we expect to see an item size of 20-bytes (total length of\n    the header struct).\n\n    >>> header = HeaderSpec(\n    >>>     fields=[field1, field2, field3],\n    >>> )\n\n    Now let's look at its data type:\n\n    >>> header.dtype\n    dtype({'names': ['foo', 'bar', 'fizz'], 'formats': ['<i4', '<i2', '<i4'], 'offsets': [0, 4, 16], 'itemsize': 20})\n\n    If we wanted to pad the end of the struct (to fit a specific byte range),\n    we would provide the item_size in the spec. If we set it to 30, this means\n    that we padded the struct by 10 bytes at the end.\n\n    >>> header = HeaderSpec(\n    >>>     fields=[field1, field2, field3],\n    >>>     item_size=30,\n    >>> )\n\n    Now let's look at its data type:\n\n    >>> header.dtype\n    dtype({'names': ['foo', 'bar', 'fizz'], 'formats': ['<i4', '<i2', '<i4'], 'offsets': [0, 4, 16], 'itemsize': 30})\n\n    To see what's going under the hood, we can look at a lower level numpy\n    description of the `dtype`. Here we observe all the gaps (void types).\n\n    >>> header.dtype.descr\n    [('foo', '<i4'), ('bar', '<i2'), ('', '|V10'), ('fizz', '<i4'), ('', '|V10')]",
         "properties": {
            "fields": {
               "description": "List containing multiple header field spec instances.",
               "items": {
                  "$ref": "#/$defs/HeaderField"
               },
               "title": "Fields",
               "type": "array"
            },
            "itemSize": {
               "anyOf": [
                  {
                     "type": "integer"
                  },
                  {
                     "type": "null"
                  }
               ],
               "default": null,
               "description": "Expected size of the struct.",
               "title": "Itemsize"
            },
            "offset": {
               "anyOf": [
                  {
                     "minimum": 0,
                     "type": "integer"
                  },
                  {
                     "type": "null"
                  }
               ],
               "default": null,
               "description": "Starting byte offset.",
               "title": "Offset"
            },
            "endianness": {
               "anyOf": [
                  {
                     "$ref": "#/$defs/Endianness"
                  },
                  {
                     "type": "null"
                  }
               ],
               "default": null,
               "description": "Endianness of structured data type."
            }
         },
         "required": [
            "fields"
         ],
         "title": "HeaderSpec",
         "type": "object"
      },
      "ScalarType": {
         "description": "A class representing scalar data types.",
         "enum": [
            "ibm32",
            "int64",
            "int32",
            "int16",
            "int8",
            "uint64",
            "uint32",
            "uint16",
            "uint8",
            "float64",
            "float32",
            "float16",
            "S8"
         ],
         "title": "ScalarType",
         "type": "string"
      },
      "TraceDataSpec": {
         "description": "A spec class for trace data (samples).",
         "properties": {
            "format": {
               "$ref": "#/$defs/ScalarType",
               "description": "Format of trace samples."
            },
            "samples": {
               "anyOf": [
                  {
                     "type": "integer"
                  },
                  {
                     "type": "null"
                  }
               ],
               "default": null,
               "description": "Number of samples in trace. It can be variable, then it must be read from each trace header.",
               "title": "Samples"
            },
            "interval": {
               "anyOf": [
                  {
                     "type": "integer"
                  },
                  {
                     "type": "null"
                  }
               ],
               "default": null,
               "description": "Sample interval of traces",
               "title": "Interval"
            }
         },
         "required": [
            "format"
         ],
         "title": "TraceDataSpec",
         "type": "object"
      }
   },
   "required": [
      "header",
      "data"
   ]
}

field header: HeaderSpec [Required]

Trace header spec.

field extHeader: HeaderSpec | None = None

Extended trace header spec.

field data: TraceDataSpec [Required]

Trace data spec.

field offset: int | None = None

Starting offset of the trace.

field endianness: Endianness | None = None

Endianness of traces and headers.

field count: int | None = None

Number of traces.

Constraints:
  • ge = 0

property dtype: dtype[Any]

Get numpy dtype.

pydantic model segy.schema.TraceDataSpec

A spec class for trace data (samples).

Show JSON schema
{
   "title": "TraceDataSpec",
   "description": "A spec class for trace data (samples).",
   "type": "object",
   "properties": {
      "format": {
         "$ref": "#/$defs/ScalarType",
         "description": "Format of trace samples."
      },
      "samples": {
         "anyOf": [
            {
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Number of samples in trace. It can be variable, then it must be read from each trace header.",
         "title": "Samples"
      },
      "interval": {
         "anyOf": [
            {
               "type": "integer"
            },
            {
               "type": "null"
            }
         ],
         "default": null,
         "description": "Sample interval of traces",
         "title": "Interval"
      }
   },
   "$defs": {
      "ScalarType": {
         "description": "A class representing scalar data types.",
         "enum": [
            "ibm32",
            "int64",
            "int32",
            "int16",
            "int8",
            "uint64",
            "uint32",
            "uint16",
            "uint8",
            "float64",
            "float32",
            "float16",
            "S8"
         ],
         "title": "ScalarType",
         "type": "string"
      }
   },
   "required": [
      "format"
   ]
}

field format: ScalarType [Required]

Format of trace samples.

field samples: int | None = None

Number of samples in trace. It can be variable, then it must be read from each trace header.

field interval: int | None = None

Sample interval of traces

property dtype: dtype[Any]

Get numpy dtype with # of samples.