mt_metadata.timeseries

mt_metadata.timeseries is a package that contains classes for describing time series metadata.

MetadataBase Objects

  • Diagnostic - Diagnostic information for data quality and instrument performance

  • Battery - Battery voltage and power supply metadata

  • Electrode - Electrode specifications and contact information

  • TimingSystem - GPS and timing system metadata (synchronization, accuracy)

  • AppliedFilter - Filters applied to time series data during acquisition or processing

  • FilterBase - Base class for all filter types (analog, digital, frequency response)

  • DataLogger - Data logger/acquisition system specifications and settings

  • Channel - Base channel metadata common to all channel types

  • ChannelBase - Fundamental channel properties and attributes

  • Auxiliary - Auxiliary channel metadata (e.g., temperature, humidity, tilt)

  • Electric - Electric field channel metadata (dipole length, orientation, electrode info)

  • Magnetic - Magnetic field channel metadata (sensor type, calibration)

  • Run - Time series run metadata (collection of channels recorded together)

  • Station - Station-level metadata (location, orientation, equipment)

  • Survey - Survey-level metadata (project information, participants, objectives)

  • Experiment - Top-level experiment metadata encompassing multiple surveys

Created on Sun Apr 24 20:50:41 2020

copyright:

Jared Peacock (jpeacock@usgs.gov)

license:

MIT

Submodules

Classes

Diagnostic

Base class for all metadata objects with Pydantic validation.

Battery

Base class for all metadata objects with Pydantic validation.

Electrode

Positional location of a geographic point

TimingSystem

Base class for all metadata objects with Pydantic validation.

AppliedFilter

Base class for all metadata objects with Pydantic validation.

FilterBase

Base class for all metadata objects with Pydantic validation.

DataLogger

Base class for all metadata objects with Pydantic validation.

Channel

Base class for all metadata objects with Pydantic validation.

ChannelBase

Base class for all metadata objects with Pydantic validation.

Auxiliary

Auxiliary channel class for storing auxiliary channel information.

Electric

Base class for all metadata objects with Pydantic validation.

Magnetic

Base class for all metadata objects with Pydantic validation.

Run

Base class for all metadata objects with Pydantic validation.

Station

Base class for all metadata objects with Pydantic validation.

Experiment

Top level of the metadata

Package Contents

class mt_metadata.timeseries.Diagnostic(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

end: Annotated[float | None, Field(default=None, description='Ending value of a diagnostic measurement.', alias=None, json_schema_extra={'examples': '10', 'type': 'number', 'units': None, 'required': False})] = None
start: Annotated[float | None, Field(default=None, description='Starting value of a diagnostic measurement.', alias=None, json_schema_extra={'examples': '12.3', 'type': 'number', 'units': None, 'required': False})] = None
class mt_metadata.timeseries.Battery(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

type: Annotated[str | None, Field(default=None, description='Description of battery type.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'pb-acid gel cell', 'type': 'string'})] = None
id: Annotated[str | None, Field(default=None, description='battery id', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'battery01', 'type': 'string'})] = None
voltage: Annotated[mt_metadata.common.StartEndRange, Field(default=StartEndRange(), description='Range of voltages.', alias=None, json_schema_extra={'units': 'volts', 'required': False, 'examples': 'Range(minimum=0.0, maximum=1.0)', 'type': 'object'})]
comments: Annotated[mt_metadata.common.Comment, Field(default_factory=Comment, description='Any comments about the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'ambient air temperature was chilly, ice on cables'})]
classmethod validate_comments(value, info)

Validate that the value is a valid comment.

class mt_metadata.timeseries.Electrode(**data)

Bases: mt_metadata.common.Location, mt_metadata.common.Instrument

Positional location of a geographic point

class mt_metadata.timeseries.TimingSystem(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

comments: Annotated[mt_metadata.common.Comment, Field(default_factory=Comment, description='Any comment on the timing system.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'GPS locked with internal quartz clock'})]
drift: Annotated[float, Field(default=0.0, description='Estimated drift of the timing system.', alias=None, json_schema_extra={'units': 'seconds', 'required': True, 'examples': '0.001'})]
type: Annotated[str, Field(default='GPS', description='Type of timing system.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': 'GPS'})]
uncertainty: Annotated[float, Field(default=0.0, description='Estimated uncertainty of the timing system.', alias=None, json_schema_extra={'units': 'seconds', 'required': True, 'examples': '0.0002'})]
n_satellites: Annotated[int | None, Field(default=None, description='Number of satellites used for timing.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': '6'})]
classmethod validate_comments(value, info)

Validate that the value is a valid comment.

class mt_metadata.timeseries.AppliedFilter(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

name: Annotated[str, Field(default=None, description='Name of the filter.', json_schema_extra={'units': None, 'required': True, 'examples': ['low pass']})]
applied: Annotated[bool, Field(default=True, description='Whether the filter has been applied.', json_schema_extra={'units': None, 'required': True, 'examples': ['True']})]
stage: Annotated[int | None, Field(default=None, description='Stage of the filter in the processing chain.', json_schema_extra={'units': None, 'required': False, 'examples': [1]})]
comments: Annotated[mt_metadata.common.comment.Comment, Field(default_factory=lambda: Comment(), description='Any comments on filters.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['low pass is not calibrated']})]
classmethod validate_comments(value, info)

Validate that the value is a valid comment.

classmethod validate_name(value, info)

Validate that the name is not empty or whitespace only. Also, replace ‘/’ with ‘ per ‘ and convert to lower case for consistency.

class mt_metadata.timeseries.FilterBase(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

name: Annotated[str, Field(default='', description='Name of filter applied or to be applied. If more than one filter input as a comma separated list.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': '"lowpass_magnetic"'})]
comments: Annotated[mt_metadata.common.Comment, Field(default_factory=lambda: Comment(), description='Any comments about the filter.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'ambient air temperature'})]
type: Annotated[str, Field(default='base', description='Type of filter, must be one of the available filters.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': 'fap_table'})]
units_in: Annotated[str, Field(default='', description="Name of the input units to the filter. Should be all lowercase and separated with an underscore, use 'per' if units are divided and '-' if units are multiplied.", alias=None, json_schema_extra={'units': None, 'required': True, 'examples': 'count'})]
units_out: Annotated[str, Field(default='', description="Name of the output units.  Should be all lowercase and separated with an underscore, use 'per' if units are divided and '-' if units are multiplied.", alias=None, json_schema_extra={'units': None, 'required': True, 'examples': 'millivolt'})]
calibration_date: Annotated[mt_metadata.common.mttime.MTime | str | float | int | numpy.datetime64 | pandas.Timestamp | None, Field(default_factory=lambda: MTime(time_stamp=None), description='Most recent date of filter calibration in ISO format of YYY-MM-DD.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': '2020-01-01'})]
gain: Annotated[float, Field(default=1.0, description='scalar gain of the filter across all frequencies, producted with any frequency depenendent terms', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': '1.0'})]
sequence_number: Annotated[int, Field(default=0, description='Sequence number of the filter in the processing chain.', alias=None, ge=0, json_schema_extra={'units': None, 'required': True, 'examples': 1})]
classmethod validate_calibration_date(field_value)
classmethod validate_comments(value, info)
classmethod validate_type(value, info)

Validate that the type of filter is set to “fir”

classmethod validate_units(value, info)

validate units base on input string will return the long name

Parameters:
  • value (units string) – unit string separated by either ‘/’ for division or ‘ ‘ for multiplication. Or ‘per’ and ‘ ‘, respectively

  • info (ValidationInfo) – _description_

Returns:

return the long descriptive name of the unit. For example ‘kilometers’.

Return type:

str

property units_in_object: mt_metadata.common.units.Unit
property units_out_object: mt_metadata.common.units.Unit
make_obspy_mapping()
property obspy_mapping

mapping to an obspy filter :rtype: dict

Type:

return

property total_gain: float

Total gain of the filter :rtype: float

Type:

return

get_filter_description()
Returns:

predetermined filter description based on the type of filter

Return type:

string

classmethod from_obspy_stage(stage, mapping=None)

Expected to return a multiply operation function

Parameters:
  • cls (filter object) – a filter object

  • stage (obspy.inventory.response.ResponseStage) – Obspy stage filter

  • mapping (dict, optional) – dictionary for mapping from an obspy stage, defaults to None

Raises:

TypeError – If stage is not a obspy.inventory.response.ResponseStage

Returns:

the appropriate mt_metadata.timeseries.filter object

Return type:

mt_metadata.timeseries.filter object

complex_response(frqs)
pass_band(frequencies, window_len=5, tol=0.5, **kwargs)

Fast passband estimation using decimation (10-100x faster than original).

Caveat: This should work for most Fluxgate and feedback coil magnetometers, and basically most filters having a “low” number of poles and zeros. This method is not 100% robust to filters with a notch in them.

Try to estimate pass band of the filter from the flattest spots in the amplitude. Instead of checking every frequency point, this decimates the frequency array and only checks a subset of windows. The pass band region is then interpolated across the full array.

The flattest spot is determined by calculating a sliding window with length window_len and estimating normalized std.

..note:: This only works for simple filters with on flat pass band.

Parameters:
  • frequencies (np.ndarray) – array of frequencies

  • window_len (integer) – length of sliding window in points

  • tol (float) – the ratio of the mean/std should be around 1 tol is the range around 1 to find the flat part of the curve.

Returns:

pass band frequencies [f_start, f_end]

Return type:

np.ndarray or None

generate_frequency_axis(sampling_rate, n_observations)
plot_response(frequencies, x_units='period', unwrap=True, pb_tol=0.1, interpolation_method='slinear')
property decimation_active

if decimation is prescribed :rtype: bool

Type:

return

class mt_metadata.timeseries.DataLogger(**data)

Bases: mt_metadata.common.Instrument

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

timing_system: Annotated[mt_metadata.timeseries.TimingSystem, Field(default_factory=TimingSystem, description='Timing system of the data logger.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'TimingSystem()'})]
firmware: Annotated[mt_metadata.common.Software, Field(default_factory=Software, description='Firmware of the data logger.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'Software()'})]
power_source: Annotated[mt_metadata.timeseries.Battery, Field(default_factory=Battery, description='Power source of the data logger.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'Battery()'})]
data_storage: Annotated[mt_metadata.common.Instrument, Field(default_factory=Instrument, description='Data storage of the data logger.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'Instrument()'})]
class mt_metadata.timeseries.Channel(**data)

Bases: ChannelBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

sensor: Annotated[mt_metadata.common.Instrument, Field(default_factory=Instrument, description='Sensor for the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': 'Instrument()'})]
location: Annotated[mt_metadata.common.BasicLocation, Field(default_factory=BasicLocation, description='Location information for the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['BasicLocation(latitude=0.0, longitude=0.0, elevation=0.0)']})]
class mt_metadata.timeseries.ChannelBase(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

channel_number: Annotated[int, Field(default=0, description='Channel number on the data logger.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1']})]
channel_id: Annotated[str | None, Field(default=None, description='channel id given by the user or data logger', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['1001.11']})]
comments: Annotated[mt_metadata.common.Comment, Field(default_factory=Comment, description='Any comments about the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['ambient air temperature was chilly, ice on cables']})]
component: Annotated[str, Field(default='auxiliary_default', description="Name of the component measured, can be uppercase and/or lowercase.  For now electric channels should start with an 'e' and magnetic channels start with an 'h', followed by the component. If there are multiples of the same channel the name could include an integer.  {type}{component}{number} --> Ex01.", alias=None, pattern='\\w+', json_schema_extra={'units': None, 'required': True, 'examples': ['ex']})]
measurement_azimuth: Annotated[float, Field(default=0.0, description='Horizontal azimuth of the channel in measurement coordinate system spcified in station.orientation.reference_frame.  Default reference frame is a geographic right-handed coordinate system with north=0, east=90, vertical=+ downward.', validation_alias=AliasChoices('measurement_azimuth', 'azimuth'), json_schema_extra={'units': 'degrees', 'required': True, 'examples': [0.0]})]
measurement_tilt: Annotated[float, Field(default=0.0, description='Vertical tilt of the channel in measurement coordinate system specified in station.orientation.reference_frame.  Default reference frame is a geographic right-handed coordinate system with north=0, east=90, vertical=+ downward.', validation_alias=AliasChoices('measurement_tilt', 'dip'), json_schema_extra={'units': 'degrees', 'required': True, 'examples': [0]})]
sample_rate: Annotated[float, Field(default=0.0, description='Digital sample rate', validation_alias=AliasChoices('sample_rate', 'sampling_rate'), json_schema_extra={'units': 'samples per second', 'required': True, 'examples': [8.0]})]
translated_azimuth: Annotated[float | None, Field(default=None, description='Horizontal azimuth of the channel in translated coordinate system, this should only be used for derived product.  For instance if you collected your data in geomagnetic coordinates and then translated them to geographic coordinates you would set measurement_azimuth=0, translated_azimuth=-12.5 for a declination angle of N12.5E.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': [0.0]})]
translated_tilt: Annotated[float | None, Field(default=None, description='Tilt of channel in translated coordinate system, this should only be used for derived product.  For instance if you collected your data using a tripod you would set measurement_tilt=45, translated_tilt=0 for a vertical component.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': [0.0]})]
type: Annotated[str, Field(default='base', description='Data type for the channel, should be a descriptive word that a user can understand.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['temperature']})]
units: Annotated[str, Field(default='', description="Units of the data, should be in SI units and represented as the full name of the unit all lowercase.  If a complex unit use 'per' and '-'.", alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['celsius']})]
data_quality: Annotated[mt_metadata.common.DataQuality, Field(default_factory=DataQuality, description='Data quality for the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['DataQuality()']})]
filters: Annotated[list[mt_metadata.timeseries.AppliedFilter], Field(default_factory=list, description='Filter data for the channel.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ["AppliedFilter(name='filter_name', applied=True, stage=1)"]})]
time_period: Annotated[mt_metadata.common.TimePeriod, Field(default_factory=TimePeriod, description='Time period for the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ["TimePeriod(start='2020-01-01', end='2020-12-31')"]})]
fdsn: Annotated[mt_metadata.common.Fdsn, Field(default_factory=Fdsn, description='FDSN information for the channel.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Fdsn()']})]
classmethod validate_component(value)

make sure the value is all lower case

classmethod validate_comments(value, info)

Validate that the value is a valid comment.

classmethod validate_units(value, info)

validate units base on input string will return the long name

Parameters:
  • value (units string) – unit string separated by either ‘/’ for division or ‘ ‘ for multiplication. Or ‘per’ and ‘ ‘, respectively

  • info (ValidationInfo) – _description_

Returns:

return the long descriptive name of the unit. For example ‘kilometers’.

Return type:

str

classmethod validate_type(value, info)

Validate that the type channel

classmethod parse_filters_string(value)

Parse string representation of filters into list of AppliedFilter objects

classmethod validate_filters(value, info)

sort the filters by stage number and check for duplicates

add_filter(applied_filter=None, name=None, applied=True, stage=None, comments=None)

Add a filter to the filter list.

Parameters:
  • name (str) – Name of the filter.

  • applied (bool, optional) – Whether the filter has been applied, by default True.

  • stage (int | None, optional) – Stage of the filter in the processing chain, by default None.

property filter_names: list[str]

List of filter names applied to the channel.

Returns:

List of filter names.

Return type:

list[str]

remove_filter(name, reset_stages=True)

Remove a filter from the filter list.

Parameters:
  • name (str) – Name of the filter to remove.

  • reset_stages (bool, optional) – Whether to reset the stages of the remaining filters, by default True.

get_filter(name)

Get a filter from the filter list by name.

Parameters:

name (str) – Name of the filter to get.

Returns:

The filter with the given name, or None if not found.

Return type:

AppliedFilter | None

channel_response(filters_dict)

full channel response from a dictionary of filter objects

property unit_object: mt_metadata.common.units.Unit

Some channels have a unit object that is used to convert between units. This is a property that returns the unit object for the channel. The unit object is created using the units attribute of the channel. The unit object is used to convert between units and to get the unit

Returns:

BaseModel object with unit attributes

Return type:

Unit

from_dict(meta_dict, skip_none=False)

Fill attributes from a dictionary with backwards compatibility for legacy filter formats.

Parameters:
  • meta_dict (dict) – Dictionary of attributes to set.

  • skip_none (bool, optional) – If True, skip attributes with None values, by default False.

Raises:

MTSchemaError – If the input dictionary is not valid.

Notes

Supports backwards compatibility for three filter formats:

  1. Legacy format (oldest): - Keys: ‘filter.applied’, ‘filter.name’ - Values: Lists of booleans and strings

  2. Old format (intermediate): - Keys: ‘filtered.applied’, ‘filtered.name’ - Values: Lists of booleans and strings

  3. New format (current): - Key: ‘filters’ - Value: List of AppliedFilter objects or dictionaries

All legacy formats are automatically converted to the new format using AppliedFilter objects. A warning is issued when legacy formats are detected.

class mt_metadata.timeseries.Auxiliary(**data)

Bases: mt_metadata.timeseries.Channel

Auxiliary channel class for storing auxiliary channel information.

type: Annotated[str, Field(default='auxiliary', description='Data type for the channel, should be a descriptive word that a user can understand.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': 'auxiliary', 'type': 'string'})]
class mt_metadata.timeseries.Electric(**data)

Bases: mt_metadata.timeseries.ChannelBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

component: Annotated[str, Field(default='e_default', description='Component of the electric field.', alias=None, pattern='^[eE][a-zA-Z0-9_]*$', json_schema_extra={'units': None, 'required': True, 'examples': ['Ex']})]
dipole_length: Annotated[float, Field(default=0.0, description='Length of the dipole as measured in a straight line from electrode to electrode.', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['55.25']})]
positive: Annotated[mt_metadata.timeseries.Electrode, Field(default_factory=Electrode, description='Positive electrode.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['Electrode()']})]
negative: Annotated[mt_metadata.timeseries.Electrode, Field(default_factory=Electrode, description='Negative electrode.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['Electrode()']})]
contact_resistance: Annotated[mt_metadata.common.StartEndRange, Field(default_factory=StartEndRange, description='Contact resistance start and end values.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['StartEndRange()']})]
ac: Annotated[mt_metadata.common.StartEndRange, Field(default_factory=StartEndRange, description='AC start and end values.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['StartEndRange()']})]
dc: Annotated[mt_metadata.common.StartEndRange, Field(default_factory=StartEndRange, description='DC start and end values.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['StartEndRange()']})]
type: Annotated[str, Field(default='electric', description='Data type for the channel, should be a descriptive word that a user can understand.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['electric']})]
class mt_metadata.timeseries.Magnetic(**data)

Bases: mt_metadata.timeseries.Channel

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

component: Annotated[str, Field(default='h_default', description='Component of the magnetic field.', alias=None, pattern='^[hHbBrR][a-zA-Z0-9_]*$', json_schema_extra={'units': None, 'required': True, 'examples': ['hx']})]
h_field_min: Annotated[mt_metadata.common.StartEndRange, Field(default_factory=StartEndRange, description='minimum of field strength at the beginning and end', alias=None, json_schema_extra={'units': 'nanotesla', 'required': True, 'examples': ['StartEndRange(start=0.01, end=0.02)']})]
h_field_max: Annotated[mt_metadata.common.StartEndRange, Field(default_factory=StartEndRange, description='maximum of field strength at the beginning and end', alias=None, json_schema_extra={'units': 'nanotesla', 'required': True, 'examples': ['StartEndRange(start=0.1, end=2.0)']})]
type: Annotated[str, Field(default='magnetic', description='Data type for the channel, should be a descriptive word that a user can understand.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['magnetic']})]
class mt_metadata.timeseries.Run(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

channels_recorded_auxiliary: Annotated[list[str], Field(default_factory=list, description='List of auxiliary channels recorded', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['[T]']})]
channels_recorded_electric: Annotated[list[str], Field(default_factory=list, description='List of electric channels recorded', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['[Ex , Ey]']})]
channels_recorded_magnetic: Annotated[list[str], Field(default_factory=list, description='List of magnetic channels recorded', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['[Hx , Hy , Hz]']})]
channels_recorded_all()

List of all channels recorded in the run.

comments: Annotated[mt_metadata.common.Comment, Field(default_factory=Comment, description='Any comments on the run.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['cows chewed cables']})]
data_type: Annotated[mt_metadata.common.DataTypeEnum, Field(default=DataTypeEnum.BBMT, description='Type of data recorded for this run.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['BBMT']})]
id: Annotated[str, Field(default='', description='Run ID should be station name followed by a number or character.  Characters should only be used if the run number is small, if the run number is high consider using digits with zeros.  For example if you have 100 runs the run ID could be 001 or {station}001.', alias=None, pattern='^[a-zA-Z0-9_]*$', json_schema_extra={'units': None, 'required': True, 'examples': ['001']})]
sample_rate: Annotated[float, Field(default=0.0, description='Digital sample rate for the run', alias=None, json_schema_extra={'units': 'samples per second', 'required': True, 'examples': ['100']})]
acquired_by: Annotated[mt_metadata.common.AuthorPerson, Field(default_factory=AuthorPerson, description='Information about the group that collected the data.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Person()']})]
metadata_by: Annotated[mt_metadata.common.AuthorPerson, Field(default_factory=AuthorPerson, description='Information about the group that collected the metadata.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Person()']})]
provenance: Annotated[mt_metadata.common.Provenance, Field(default_factory=Provenance, description='Provenance information about the run.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Provenance()']})]
time_period: Annotated[mt_metadata.common.TimePeriod, Field(default_factory=TimePeriod, description='Time period for the run.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ["TimePeriod(start='2020-01-01', end='2020-12-31')"]})]
data_logger: Annotated[mt_metadata.timeseries.DataLogger, Field(default_factory=DataLogger, description='Data Logger information used to collect the run.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['DataLogger()']})]
fdsn: Annotated[mt_metadata.common.Fdsn, Field(default_factory=Fdsn, description='FDSN information for the run.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Fdsn()']})]
channels: Annotated[mt_metadata.common.list_dict.ListDict | list | dict | collections.OrderedDict, Field(default_factory=ListDict, description='ListDict of channel objects collected in this run.', alias=None, exclude=True, json_schema_extra={'units': None, 'required': False, 'examples': ['ListDict(Electric(), Magnetic(), Auxiliary())']})]
classmethod validate_comments(value, info)

Validate that the value is a valid comment.

classmethod validate_data_type(value, info)

Validate that the data_type is a string.

classmethod validate_list_of_strings(value, info)

Validate that the value is a list of strings.

validate_channels_recorded()

Validate that the value is a list of strings.

classmethod validate_channels(value, info)
merge(other, inplace=True)

Merge channels from another Run into this run.

Combines channels from two runs and updates the channels recorded lists and time period.

Parameters:
  • other (Run) – Another Run object whose channels will be merged into this run.

  • inplace (bool, optional) – If True, update this run and update time period. If False, return a copy of the merged run (default is True).

Returns:

If inplace is False, returns a copy of the merged Run. Otherwise None.

Return type:

Run | None

Raises:

TypeError – If other is not a Run object.

Examples

Merge runs in place:

>>> run1 = Run(id='001')
>>> run1.add_channel(Electric(component='ex'))
>>> run2 = Run(id='002')
>>> run2.add_channel(Magnetic(component='hx'))
>>> run1.merge(run2, inplace=True)
>>> print(run1.channels_recorded_all)
['ex', 'hx']

Merge and return new run:

>>> merged_run = run1.merge(run2, inplace=False)
>>> print(merged_run.channels_recorded_all)
['ex', 'hx']

See also

update

Update metadata from another run

update(other, match=[])

Update attribute values from another Run object.

Copies non-None, non-default attribute values from another Run object to this one. Skips empty values like None, 0.0, [], empty strings, and default timestamps.

Parameters:
  • other (Run) – Another Run object to copy attributes from.

  • match (list[str] | None, optional) – List of attribute names that must match between runs before updating. If any don’t match, raises ValueError. Typically used for ‘id’ to ensure runs are compatible (default is None).

Raises:
  • ValueError – If any attributes in match list don’t have equal values.

  • TypeError – If other is not a compatible Run type.

Examples

Basic update:

>>> run1 = Run(id='001', sample_rate=256.0)
>>> run2 = Run(id='001', sample_rate=0.0)
>>> run2.acquired_by.author = 'J. Doe'
>>> run1.update(run2)
>>> print(run1.acquired_by.author)
'J. Doe'
>>> print(run1.sample_rate)  # Not updated (run2 has default 0.0)
256.0

Update with matching check:

>>> run1 = Run(id='001')
>>> run2 = Run(id='002')
>>> try:
...     run1.update(run2, match=['id'])
... except ValueError as e:
...     print("IDs don't match!")
IDs don't match!

Notes

Channel metadata is also updated. For each channel in other, if the channel exists in this run, it’s updated; if not, it’s added.

Skipped values:

  • None

  • 0.0

  • Empty lists []

  • Empty strings ‘’

  • Default timestamp ‘1980-01-01T00:00:00+00:00’

See also

merge

Merge channels from another run

has_channel(component)

Check if a channel with the given component exists in the run.

Parameters:

component (str) – Channel component name to search for (e.g., ‘ex’, ‘hy’).

Returns:

True if channel exists, False otherwise.

Return type:

bool

Examples

>>> run = Run(id='001')
>>> run.add_channel(Electric(component='ex'))
>>> print(run.has_channel('ex'))
True
>>> print(run.has_channel('ey'))
False

See also

get_channel

Retrieve a channel object

channel_index

Get the index of a channel

channel_index(component)

Get the index of a channel in the channels_recorded_all list.

Parameters:

component (str) – Channel component name to search for (e.g., ‘ex’, ‘hy’).

Returns:

Index of the channel if found, None otherwise.

Return type:

int | None

Examples

>>> run = Run(id='001')
>>> run.add_channel(Electric(component='ex'))
>>> run.add_channel(Electric(component='ey'))
>>> run.add_channel(Magnetic(component='hx'))
>>> print(run.channel_index('ey'))
1
>>> print(run.channel_index('hz'))
None

Notes

Channels are sorted alphabetically in channels_recorded_all.

See also

has_channel

Check if channel exists

get_channel

Retrieve channel object

get_channel(component)

Retrieve a channel object by component name.

Parameters:

component (str) – Channel component name to retrieve (e.g., ‘ex’, ‘hy’).

Returns:

Channel object if found, None otherwise. Return type depends on the channel type.

Return type:

Electric | Magnetic | Auxiliary | None

Examples

>>> run = Run(id='001')
>>> ex = Electric(component='ex', dipole_length=100.0)
>>> run.add_channel(ex)
>>> channel = run.get_channel('ex')
>>> print(type(channel).__name__)
'Electric'
>>> print(channel.dipole_length)
100.0
>>> print(run.get_channel('ey'))
None

See also

has_channel

Check if channel exists

add_channel

Add a channel to the run

add_channel(channel_obj, update=True)

Add or update a channel in the run.

If the channel already exists (matched by component), its metadata is updated. If it doesn’t exist, it’s added to the channels list. Can accept channel objects, dictionaries, or component strings.

Parameters:
  • channel_obj (Electric | Magnetic | Auxiliary | dict | str) –

    Channel to add. Can be:

    • Channel object (Electric, Magnetic, or Auxiliary)

    • Dictionary with channel attributes (must include ‘type’ or ‘component’)

    • String component name (e.g., ‘ex’, ‘hy’, ‘temp’)

    If string, channel type is inferred:

    • Starts with ‘e’ → Electric

    • Starts with ‘h’ or ‘b’ or equals ‘magnetic’ → Magnetic

    • Otherwise → Auxiliary

  • update (bool, optional) – If True, update the run’s time period to include this channel’s time period. If False, don’t update time period (default is True).

Examples

Add channel objects:

>>> run = Run(id='001')
>>> ex = Electric(component='ex', dipole_length=100.0)
>>> run.add_channel(ex)
>>> print(run.channels_recorded_electric)
['ex']

Add from string (infers type):

>>> run.add_channel('hy')
>>> run.add_channel('temperature')
>>> print(run.channels_recorded_magnetic)
['hy']
>>> print(run.channels_recorded_auxiliary)
['temperature']

Add from dictionary:

>>> channel_dict = {
...     'type': 'electric',
...     'component': 'ey',
...     'dipole_length': 95.0
... }
>>> run.add_channel(channel_dict)

Update existing channel:

>>> ex_updated = Electric(component='ex', dipole_length=105.0)
>>> run.add_channel(ex_updated)  # Updates existing 'ex'
>>> print(run.get_channel('ex').dipole_length)
105.0

Add without updating time period:

>>> run.add_channel('hz', update=False)

Notes

This method automatically:

  • Updates channels_recorded lists

  • Updates run time period (if update=True)

  • Converts string/dict inputs to proper channel objects

  • Logs when updating existing channels

See also

remove_channel

Remove a channel from the run

get_channel

Retrieve a channel object

update_time_period

Manually update time period

remove_channel(channel_id)

Remove a channel from the run.

Parameters:

channel_id (str) – Channel component name to remove (e.g., ‘ex’, ‘hy’).

Examples

>>> run = Run(id='001')
>>> run.add_channel(Electric(component='ex'))
>>> run.add_channel(Electric(component='ey'))
>>> print(run.channels_recorded_electric)
['ex', 'ey']
>>> run.remove_channel('ex')
>>> print(run.channels_recorded_electric)
['ey']
>>> run.remove_channel('ez')  # Doesn't exist
# Logs warning: Could not find ez to remove.

Notes

Automatically updates the channels_recorded lists after removal. Logs a warning if the channel is not found.

See also

add_channel

Add a channel to the run

has_channel

Check if channel exists

update_channel_keys()

Update channel dictionary keys to match current component values.

Updates the keys in the channels ListDict to match current channel components. Useful when channel components have been modified after channels were added, ensuring channels can be accessed by their current component values.

Returns:

Mapping of old keys to new keys showing what was changed.

Return type:

dict[str, str]

Examples

Fix keys after modifying components:

>>> run = Run(id='001')
>>> channel = Electric(component='')
>>> run.add_channel(channel)
>>> # Channel is stored with empty string key
>>> channel.component = 'ex'
>>> key_mapping = run.update_channel_keys()
>>> print(key_mapping)
{'': 'ex'}
>>> # Now accessible as run.channels['ex']
>>> print(run.get_channel('ex').component)
'ex'

Multiple key updates:

>>> run = Run(id='001')
>>> ch1 = Electric(component='e1')
>>> ch2 = Magnetic(component='h1')
>>> run.add_channel(ch1)
>>> run.add_channel(ch2)
>>> ch1.component = 'ex'
>>> ch2.component = 'hx'
>>> mapping = run.update_channel_keys()
>>> print(mapping)
{'e1': 'ex', 'h1': 'hx'}

Notes

This is typically only needed if you’ve directly modified channel component attributes after adding them to the run. Normal usage doesn’t require calling this method.

See also

add_channel

Add channels to the run

get_channel

Access channels by component

property n_channels: int

Number of channels in the run.

Returns:

Count of channels currently in the run.

Return type:

int

Examples

>>> run = Run(id='001')
>>> print(run.n_channels)
0
>>> run.add_channel('ex')
>>> run.add_channel('hy')
>>> print(run.n_channels)
2
update_time_period()

Update run’s time period to encompass all channel time periods.

Examines all channels in the run and updates the run’s start and end times to include the earliest start and latest end from all channels. Ignores default timestamp ‘1980-01-01T00:00:00+00:00’.

Examples

>>> from mt_metadata.timeseries import Run, Electric
>>> run = Run(id='001')
>>> ex = Electric(component='ex')
>>> ex.time_period.start = '2020-01-01T00:00:00+00:00'
>>> ex.time_period.end = '2020-01-01T01:00:00+00:00'
>>> run.add_channel(ex, update=False)
>>> print(run.time_period.start)
1980-01-01T00:00:00+00:00
>>> run.update_time_period()
>>> print(run.time_period.start)
2020-01-01T00:00:00+00:00

Multiple channels:

>>> ey = Electric(component='ey')
>>> ey.time_period.start = '2020-01-01T00:30:00+00:00'
>>> ey.time_period.end = '2020-01-01T02:00:00+00:00'
>>> run.add_channel(ey, update=True)
>>> print(run.time_period.start)  # Uses earliest
2020-01-01T00:00:00+00:00
>>> print(run.time_period.end)  # Uses latest
2020-01-01T02:00:00+00:00

Notes

  • Only updates if channels exist (n_channels > 0)

  • Ignores channels with default timestamp

  • Always expands time period, never shrinks it

  • Automatically called by add_channel() when update=True

See also

add_channel

Add channel and optionally update time period

class mt_metadata.timeseries.Station(**data)

Bases: mt_metadata.base.MetadataBase

Base class for all metadata objects with Pydantic validation.

MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.

_skip_equals

Private attribute listing fields to skip in equality comparisons

Type:

list[str]

_fields

Private attribute caching field information

Type:

dict[str, Any]

Notes

  • All field assignments are validated automatically via Pydantic

  • None values are converted to appropriate defaults (empty string or 0.0)

  • Supports nested attribute access via dot notation

  • Thread-safe for read operations after initialization

channel_layout: Annotated[mt_metadata.common.ChannelLayoutEnum, Field(default=ChannelLayoutEnum.X, description='How the station channels were laid out.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['X']})]
channels_recorded: Annotated[list[str], Field(default_factory=list, description='List of components recorded by the station. Should be a summary of all channels recorded. Dropped channels will be recorded in Run metadata.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['"[ Ex, Ey, Hx, Hy, Hz, T]"']})]
comments: Annotated[mt_metadata.common.Comment, Field(default_factory=Comment, description='Any comments on the station.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['cows chewed cables']})]
data_type: Annotated[mt_metadata.common.DataTypeEnum, Field(default='BBMT', description='Type of data recorded. If multiple types input as a comma separated list.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['BBMT']})]
fdsn: Annotated[mt_metadata.common.Fdsn, Field(default_factory=Fdsn, description='FDSN information for the station.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Fdsn()']})]
geographic_name: Annotated[str, Field(default='', description='Closest geographic name to the station, usually a city, but could be another common geographic location.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['Whitehorse, YK']})]
id: Annotated[str, Field(default='', description='Station ID name.  This should be an alpha numeric name that is typically 5-6 characters long.  Commonly the project name in 2 or 3 letters and the station number.', alias=None, pattern='^[a-zA-Z0-9_-]*$', json_schema_extra={'units': None, 'required': True, 'examples': ['MT001']})]
run_list: Annotated[list[str], Field(default_factory=list, description='List of runs recorded by the station. Should be a summary of all runs recorded.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['[ mt001a, mt001b, mt001c ]']})]
location: Annotated[mt_metadata.common.StationLocation, Field(default_factory=StationLocation, description='Location of the station.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['StationLocation(latitude=60.0, longitude=-135.0)']})]
orientation: Annotated[mt_metadata.common.Orientation, Field(default_factory=Orientation, description='Orientation of the station.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Orientation(north=0, east=0, vertical=1)']})]
acquired_by: Annotated[mt_metadata.common.AuthorPerson, Field(default_factory=AuthorPerson, description='Group or person who acquired the data.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Person()']})]
provenance: Annotated[mt_metadata.common.Provenance, Field(default_factory=Provenance, description='Provenance of the data.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Provenance()']})]
time_period: Annotated[mt_metadata.common.TimePeriod, Field(default_factory=TimePeriod, description='Time period of the data.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ["TimePeriod(start='2020-01-01', end='2020-12-31')"]})]
runs: Annotated[mt_metadata.common.list_dict.ListDict | list | dict | collections.OrderedDict | tuple, Field(default_factory=ListDict, description='List of runs recorded by the station.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ["[Run(id='mt001a'), Run(id='mt001b'), Run(id='mt001c')]"]})]
classmethod validate_comments(value, info)
classmethod validate_list_of_strings(value, info)

Validate that the value is a list of strings.

validate_runs_and_channels_recorded()

Validate that the value is a list of strings.

validate_station_id()

Validate that the value is a list of strings.

classmethod validate_runs(value, info)
merge(other, inplace=False)
property n_runs: int

Return the number of runs in the station.

Returns:

number of runs in the station

Return type:

int

has_run(run_id)

Check to see if the run id already exists

Parameters:

run_id (string) – run id verbatim

Returns:

Tru if exists, False if not

Return type:

boolean

run_index(run_id)

Get the index of the run_id

Parameters:

run_id (string) – run id verbatim

Returns:

index of the run

Return type:

integer

update_channels_recorded()

Update the channels recorded lists based on the channels in the run.

update_run_list()

Update the run list based on the runs in the station.

update_time_period()

update time period from run information

update_all()

Update the time period, channels recorded and run list.

add_run(run_obj, update=True)

Add a run, if one of the same name exists overwrite it.

Parameters:

run_obj (mt_metadata.timeseries.Run) – run object to add

get_run(run_id)

Get a mt_metadata.timeseries.Run object from the given id

Parameters:

run_id (string) – run id verbatim

remove_run(run_id, update=True)

remove a run from the survey

Parameters:

run_id (string) – run id verbatim

update_run_keys()

Update the keys in the runs ListDict to match current run IDs.

This is useful when run IDs have been modified after runs were added to the station, ensuring that runs can be accessed by their current ID values.

Returns:

mapping of old keys to new keys

Return type:

dict

Example

>>> station = Station()
>>> run = Run()
>>> run.id = ""  # empty ID initially
>>> station.add_run(run)
>>> run.id = "001"  # update the ID
>>> key_mapping = station.update_run_keys()
>>> print(key_mapping)  # {'': '001'}
>>> # Now run can be accessed as station.runs['001']
sort_runs_by_time(inplace=True, ascending=True)

return a list of runs sorted by start time in the order of ascending or descending.

Parameters:

ascending (TYPE, optional) – DESCRIPTION, defaults to True

Returns:

DESCRIPTION

Return type:

TYPE

class mt_metadata.timeseries.Experiment(**data)

Bases: mt_metadata.base.MetadataBase

Top level of the metadata

surveys: Annotated[mt_metadata.common.list_dict.ListDict | list | dict | collections.OrderedDict, Field(default_factory=ListDict, description='List of surveys in the experiment', title='List of Surveys', json_schema_extra={'required': False, 'units': None, 'examples': [{'id': 'survey_1'}, {'id': 'survey_2'}]})]
merge(other)

Merge two Experiment objects

property n_surveys: int
classmethod validate_surveys(value)

set the survey list

property survey_names: list[str]

Return names of surveys in experiment

has_survey(survey_id)

Has survey id

Parameters:

survey_id (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

survey_index(survey_id)

Get survey index

Parameters:

survey_id (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

add_survey(survey_obj)

Add a survey, if has the same name update that object.

Parameters:

survey_obj (:class:`mt_metadata.timeseries.Survey) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

get_survey(survey_id)

Get a survey from the survey id

Parameters:

survey_id (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

remove_survey(survey_id, update=True)

Remove a survey from the experiment

Parameters:

survey_id (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

to_dict(nested=False, required=True)

create a dictionary for the experiment object.

Parameters:
  • nested (TYPE, optional) – DESCRIPTION, defaults to False

  • single (TYPE, optional) – DESCRIPTION, defaults to False

  • required (TYPE, optional) – DESCRIPTION, defaults to True

Returns:

DESCRIPTION

Return type:

TYPE

from_dict(ex_dict, skip_none=True)

fill from an input dictionary

Parameters:

ex_dict (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

to_json(fn=None, nested=False, indent=' ' * 4, required=True)

Write a json string from a given object, taking into account other class objects contained within the given object.

Parameters:

nested ([ True | False ] , default is False) – make the returned json nested

from_json(json_str, skip_none=True)

read in a json string and update attributes of an object

Parameters:

json_str (string or pathlib.Path) – json string or file path

to_xml(fn=None, required=True, sort=True)

Write XML version of the experiment

Parameters:

fn (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

from_xml(fn=None, element=None, sort=True, skip_none=True)
Parameters:
  • fn (TYPE, optional) – DESCRIPTION, defaults to None

  • element (TYPE, optional) – DESCRIPTION, defaults to None

Returns:

DESCRIPTION

Return type:

TYPE

to_pickle(fn=None)

Write a pickle version of the experiment

Parameters:

fn (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

from_pickle(fn=None)

Read pickle version of experiment

Parameters:

fn (TYPE) – DESCRIPTION

Returns:

DESCRIPTION

Return type:

TYPE

sort(inplace=True)

sort surveys, stations, runs, channels alphabetically/numerically

Parameters:

inplace (TYPE, optional) – DESCRIPTION, defaults to True

Returns:

DESCRIPTION

Return type:

TYPE