Columns#
Note
The output under each example on this page is from runs on CHPC on 12 October 2026 (why it is recorded).
The columns you get depend on the instrument and on the data level you
read (raw, qaqc, calibrated or final; see The four levels). This page says what the columns are, level by level,
for the instruments you are most likely to use. Each section says which
instrument and level its examples come from.
The examples print wide tables. These two pandas settings print them in full, whatever the width of your terminal:
>>> import pandas as pd
>>> import uataq
>>> pd.set_option("display.width", 120)
>>> pd.set_option("display.max_columns", None)
In every table#
The index is
Time_UTC, the time of the measurement in UTC, without a time zone attached. Your first data shows how to convert it to local time.The concentration columns follow one naming pattern for every instrument, level and research group:
CO2d_ppm_cal,O3_ppb,PM2.5_ugm3and so on. Column names explains the pattern.get_obs()andget_network_obs()add aninstrumentcolumn after the concentration columns, a text column that names the instrument each row came from. Take a mean withmean(numeric_only=True)to leave it out.uataq renames many of the instruments’ other columns to common names, so that a quantity has the same name across instruments and groups. For example, the
lgr_ugga’s cavity pressure isCavity_P_torrin the pipeline’s files andInternal_P_torrin uataq. The renaming is inlin.column_mappingandhorel.column_mapping. Keep this in mind when you read the pipeline’s own documentation, which uses the names in its files.
Column names#
Concentration columns follow {pollutant}[d|channel]_{units}[_cal|_raw]:
O3_ppb, CO2d_ppm_cal (dry mole fraction, calibrated), CH4d_ppm_raw,
PM2.5_ugm3, BC6_ngm3 (aethalometer channel 6).
import uataq
from uataq.pollutants import concentration_columns, parse_column
obs = uataq.get_obs("WBB", "CO2", time_range="2024-01")
obs[concentration_columns("CO2", obs.columns)] # CO2d_ppm_cal, not diagnostics
parse_column("CH4d_ppm_raw") # pollutant='CH4', units='ppm', dry=True, calibration='raw'
The two functions are documented on the uataq.pollutants page.
_cal vs _raw: in lin final data _cal is the calibrated value and
_raw the uncalibrated one, except for TRX01’s lgr_ugga_manual_cal. That
exception, and the rows where _cal is empty, are explained under
When _cal is empty.
Labels, units and expected ranges for plotting are the same for every instrument,
so uataq leaves them to lair, the group’s
atmospheric-science toolkit: lair.pollutants.get_pollutant("CH4").label().
The CO2 and CH4 analyzers#
This section is about the lin group’s greenhouse gas analyzers: the
lgr_ugga (a Los Gatos Research analyzer, which measures CO2 and CH4) and the
licor_6262 and licor_7000 (LI-COR analyzers, which measure CO2 only).
They are the only instruments with a calibrated level. Each row is one
record of the analyzer, about every 10 seconds. The examples read the
lgr_ugga at WBB on 2 June 2025 and the licor_7000 at SUG on the same day.
What each level holds, and which rows final keeps, is on
Data levels and flags.
Final#
>>> final = uataq.read_data("WBB", "lgr_ugga", time_range="2025-06-02")["lgr_ugga"]
>>> final.head(3)
CO2d_ppm_cal CO2d_ppm_raw CH4d_ppm_cal CH4d_ppm_raw H2O_ppm
Time_UTC
2025-06-02 00:00:01 431.852558 434.8026 1.981142 1.979105 7088.775
2025-06-02 00:00:11 431.612346 434.5594 1.980728 1.978685 7101.099
2025-06-02 00:00:21 431.812938 434.7615 1.980816 1.978773 7150.829
Column |
Meaning |
|---|---|
|
CO2 dry mole fraction in ppm, calibrated against the site’s reference tanks. Can be empty; see When _cal is empty. |
|
The same measurement before calibration. |
|
The same for CH4, in ppm ( |
|
Water vapor in ppm, taken from the |
The licor_7000 has the same columns without the CH4 ones:
>>> uataq.read_data("SUG", "licor_7000", time_range="2025-06-02")["licor_7000"].columns.tolist()
['CO2d_ppm_cal', 'CO2d_ppm_raw', 'H2O_ppm']
get_obs() returns the concentration columns of this level, so
get_obs("WBB", "CO2") gives CO2d_ppm_cal and CO2d_ppm_raw.
Calibrated#
>>> cal = uataq.read_data("WBB", "lgr_ugga", lvl="calibrated", time_range="2025-06-02")["lgr_ugga"]
>>> cal.columns.tolist()
['CO2d_ppm_cal', 'CO2d_ppm_raw', 'CO2d_m', 'CO2d_b', 'CO2d_n', 'CO2d_rsq', 'CO2d_rmse', 'ID_CO2', 'CH4d_ppm_cal', 'CH4d_ppm_raw', 'CH4d_m', 'CH4d_b', 'CH4d_n', 'CH4d_rsq', 'CH4d_rmse', 'ID_CH4', 'QAQC_Flag']
>>> cal[["CO2d_ppm_cal", "CO2d_ppm_raw", "CO2d_m", "CO2d_b", "CO2d_n", "CO2d_rsq", "CO2d_rmse"]].head(3)
CO2d_ppm_cal CO2d_ppm_raw CO2d_m CO2d_b CO2d_n CO2d_rsq CO2d_rmse
Time_UTC
2025-06-02 00:00:01 431.852558 434.8026 1.010199 -1.454323 3 0.999998 0.060986
2025-06-02 00:00:11 431.612346 434.5594 1.010198 -1.454345 3 0.999998 0.060964
2025-06-02 00:00:21 431.812938 434.7615 1.010196 -1.454367 3 0.999998 0.060943
The pipeline calibrates each analyzer with the reference tanks it measures every
few hours: it fits a straight line between the tanks’ measured and known
values, for every row. The pipeline’s
calibration page
describes the method. The fit columns, for CO2 (the CH4 ones start with
CH4d_):
Column |
Meaning |
|---|---|
|
The uncalibrated value: the |
|
The slope and intercept of the fit. The calibrated value is
|
|
How many reference tanks the fit used at that time. With one tank the fit
is a slope only ( |
|
The fit’s R² and root mean square error (in ppm). Empty when the fit used fewer than three tanks. |
|
What the analyzer was sampling; see What the analyzer was sampling. |
|
The |
The formula holds to rounding:
>>> ((cal["CO2d_ppm_raw"] - cal["CO2d_b"]) / cal["CO2d_m"] - cal["CO2d_ppm_cal"]).abs().max()
np.float64(2.8421709430404007e-12)
QAQC#
>>> qaqc = uataq.read_data("WBB", "lgr_ugga", lvl="qaqc", time_range="2025-06-02")["lgr_ugga"]
>>> qaqc.columns.tolist()
['CH4_ppm', 'CH4_ppm_sd', 'H2O_ppm', 'H2O_ppm_sd', 'CO2_ppm', 'CO2_ppm_sd', 'CH4d_ppm', 'CH4d_ppm_sd', 'CO2d_ppm', 'CO2d_ppm_sd', 'Internal_P_torr', 'Internal_P_torr_sd', 'Internal_T_C', 'Internal_T_C_sd', 'Ambient_T_C', 'Ambient_T_C_sd', 'RingDown0_us', 'RingDown0_us_sd', 'RingDown1_us', 'RingDown1_us_sd', 'Fit_Flag', 'ID', 'ID_CO2', 'ID_CH4', 'QAQC_Flag']
Column |
Meaning |
|---|---|
|
The mole fractions in the sampled (wet) air, in ppm, not calibrated. |
|
The dry mole fractions, not calibrated. They are the |
|
A standard deviation that the |
|
A status number that the |
|
What the analyzer was sampling; see What the analyzer was sampling. |
|
The pipeline’s flag; see Flags. |
|
The analyzer’s own measurements of its state (cavity pressure and
temperature, and so on), with their |
The licor_6262 and licor_7000 have other instrument columns at this
level (flow, pressure, temperature, the logger’s battery voltage). Print
columns to see them. Their Analog_H2O_ppth is the analyzer’s own water
vapor reading, in parts per thousand (not ppm like H2O_ppm, which the
pipeline computes from the cavity’s humidity and pressure).
Other instruments#
The lin group’s other instruments (the Teledyne analyzers, the 2B ozone
monitor, the MetOne particle monitor, and so on) have no calibrated level
and no _cal or _raw columns. Their qaqc level has the instrument’s
columns and QAQC_Flag; their final level keeps the rows that pass
QAQC and only a few columns. For the teledyne_t400 (ozone) at
WBB on 2 June 2025:
>>> ozone = uataq.read_data("WBB", "teledyne_t400", lvl="qaqc", time_range="2025-06-02")["teledyne_t400"]
>>> ozone.columns.tolist()
['O3_ppb_std', 'O3_Meas_mV', 'O3_Ref_mV', 'O3_Gen_mV', 'O3_Drive_mV', 'Photo_Power_mV', 'Internal_P_inHgA', 'Flow_mLpm', 'Internal_T_C', 'Photo_Lamp_T_C', 'O3_Scrub_T_C', 'O3_Gen_T_C', 'Instrument_T_C', 'Slope', 'Offset', 'O3_ppb', 'Test_mV', 'QAQC_Flag']
>>> uataq.read_data("WBB", "teledyne_t400", time_range="2025-06-02")["teledyne_t400"].columns.tolist()
['O3_ppb']
The pipeline lists the columns of every instrument and level in its data_config.json, with the names in its files, before uataq renames them.
The horel group’s instruments#
The TRAX trains and the buses also carry instruments run by the horel group
(ozone, particles, NOx; see Research group). Their qaqc and final levels
are read from the same horel files, and their columns are named like the lin
group’s. The qaqc level of the ozone monitor (2b_205) on TRX01 on 1 June
2024 has:
>>> o3 = uataq.read_data("TRX01", "2b_205", lvl="qaqc", group="horel", time_range="2024-06-01")["2b_205"]
>>> o3.columns.tolist()
['O3_ppb', 'Flow_Lpm', 'Internal_T_C', 'Internal_P_hPa', 'QAQC_Flag']
Their flags are 0 or -1 (see Flags).
Next#
Data levels and flags: what each level is for, what
finalkeeps, the flags, and the rows where_calis empty.uataq.pollutants: the functions that pick the concentration columns out of a table and parse their names.