How to read meteorological data with read_mdf function

from __future__ import annotations

import pandas as pd

from cdm_reader_mapper import properties, read_mdf, test_data

The cdm_reader_mapper.read_mdf function and is a tool designed to read data files compliant with a user specified data model.

It was developed with the initial idea to read the IMMA data format, but it was further enhanced to account for other meteorological data formats.

Lets see an example for a typical file from ICOADSv3.0.. We pick an specific monthly output for a Source/Deck. In this case data from the Marine Meterological Journals data set SID/DCK: 125-704 for Oct 1878.

The .imma file looks like this:

data_path = test_data.test_icoads_r300_d704["source"]

data_ori = pd.read_table(data_path)
data_ori.head()
18781020 600 4228 29159 130623 10Panay 12325123 9961 4 165 17128704125 5 0 1 1FF111F11AAA1AAAA1AAA 9815020N163002199 0 100200180003Panay 78011118737S.P.Bray,Jr 013231190214 Bulkhead of cabin 1- .1022200200180014Boston Rio de Janeiro 300200180014001518781020 4220N 6630W 10 E 400200180014001518781020102 85 EXS WSW 0629601 58 BOC CU05R
0 18781020 800 4231 29197 130623 10Panay 1...
1 187810201000 4233 29236 130623 10Panay 1...
2 187810201200 4235 29271 130623 10Panay 1...
3 187810201400 4237 29310 130623 10Panay 1...

Very messy to just read into python!

This is why we need the mdf_reader tool, to helps us put those imma files in a pandas.DataFrame format. For that we need need a schema.

A schema file gathers a collection of descriptors that enable the mdf_reader tool to access the content of a data model/ schema and extract the sections of the raw data file that contains meaningful information. These schema files are the bones of the data model, basically .json files outlining the structure of the incoming raw data.

The mdf_reader takes this information and translate the characteristics of the data to a python pandas dataframe.

The tool has several schema templates build in.

properties.SupportedDataModels
typing.Literal['craid', 'gdac', 'icoads', 'pub47', 'marob', 'cmems']

Schemas can be designed to be deck specific like the example below

schema = "icoads_r300_d704"

data = read_mdf(data_path, imodel=schema)
WARNING:root:Unknown column_type 'object' for column '('c8', 'PUID')'
WARNING:root:Unknown column_type 'object' for column '('c95', 'ARCR')'
WARNING:root:Unknown column_type 'object' for column '('c96', 'ARCI')'
WARNING:root:Unknown column_type 'object' for column '('c97', 'ARCE')'
WARNING:root:Unknown column_type 'object' for column '('c99_sentinel', 'BLK')'
/home/docs/checkouts/readthedocs.org/user_builds/cdm-reader-mapper/conda/latest/lib/python3.13/site-packages/cdm_reader_mapper/mdf_reader/utils/validators.py:240: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  to_bool = data[validated_columns].applymap(convert_str_boolean)
/home/docs/checkouts/readthedocs.org/user_builds/cdm-reader-mapper/conda/latest/lib/python3.13/site-packages/cdm_reader_mapper/mdf_reader/utils/validators.py:241: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  false_mask = to_bool.applymap(_is_false)
/home/docs/checkouts/readthedocs.org/user_builds/cdm-reader-mapper/conda/latest/lib/python3.13/site-packages/cdm_reader_mapper/mdf_reader/utils/validators.py:242: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  true_mask = to_bool.applymap(_is_true)

A new schema can be build for a particular deck and source as shown in this notebook. The imma1_d704 schema was build upon the imma1 schema/data model but extra sections have been added to the .json files to include supplemental data from ICOADS documentation. This is a snapshot of the data inside the imma1_d704.json.

"c99_journal": {
            "header": {"sentinal": "1", "field_layout":"fixed_width","length": 117},
            "elements": {
              "sentinal":{
                  "description": "Journal header record identifier",
                  "field_length": 1,
                  "column_type": "str"
              },
              "reel_no":{
                  "description": "Microfilm reel number. See if we want the zero padding or not...",
                  "field_length": 3,
                  "column_type": "str",
                  "LMR6": true
              }
            ...

Now metadata information can be extracted as a component of the padas dataframe.

data.data.c99_journal
sentinel reel_no journal_no frame_no ship_name journal_ed rig ship_material vessel_type vessel_length ... hold_depth tonnage baro_type baro_height baro_cdate baro_loc baro_units baro_cor thermo_mount SST_I
0 1 002 0018 0003 Panay 78 01 1 1 187 ... 23 1190 2 14 None Bulkhead of cabin 1 - .102 2 None
1 1 002 0018 0003 Panay 78 01 1 1 187 ... 23 1190 2 14 None Bulkhead of cabin 1 - .102 2 None
2 1 002 0018 0003 Panay 78 01 1 1 187 ... 23 1190 2 14 None Bulkhead of cabin 1 - .102 2 None
3 1 002 0018 0003 Panay 78 01 1 1 187 ... 23 1190 2 14 None Bulkhead of cabin 1 - .102 2 None
4 1 002 0018 0003 Panay 78 01 1 1 187 ... 23 1190 2 14 None Bulkhead of cabin 1 - .102 2 None

5 rows × 24 columns

To learn how to construct a schema or data model for a particular deck/source, visit this other tutorial notebook