Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/NASAARSET/PM2.5_AQ_Online_2026/llms.txt

Use this file to discover all available pages before exploring further.

SINCA (Sistema de Información Nacional de Calidad del Aire) is Chile’s official national air quality monitoring network, operated by the Ministerio del Medio Ambiente. The public portal at sinca.mma.gob.cl exposes hourly time series in three validation tiers — validated, preliminary, and not-validated — for PM₂.₅ and other pollutants at stations distributed across Chile’s administrative regions. The ARSET 2026 case study uses SINCA as the primary ground-truth source instead of OpenAQ for the Chile central-valley region (December 2022 – March 2023). The family of functions described on this page (get_sinca_region_stations, get_sinca_station_metadata, F_get_SINCA_from_web) scrapes the portal programmatically and returns data in the identical (lat, lon, time) DataFrame format produced by F_get_OpenAQ_from_API, so all downstream analysis cells work unchanged.
SINCA does not expose a formal REST API — data are retrieved by scraping HTML station pages and a legacy CGI time-series endpoint. Rate-limit your requests with a short sleep (time.sleep(0.2)) between stations to avoid overloading the server.

Why SINCA instead of OpenAQ?

For recent or extreme episodes, two differences make SINCA the better choice:
AspectOpenAQSINCA
Temporal resolution24-hour rolling average (from Chilean feeds)1-hour average
Data tiers availableValidated only (during ingestion lag)Validated → Preliminary → Not-validated
Fire episode coverageMissing highest peaks (not yet validated)Full episode coverage
Geographic scopeGlobal aggregatorChile only
During the February 2023 megafire episode, OpenAQ reported smooth 24-hour averages while SINCA’s hourly not-validated records captured PM₂.₅ spikes exceeding 200 µg/m³. See the OpenAQ page for a direct comparison plot.
In general, always check the original local data source when studying recent or extreme events. The researchers and network operators who collected the data will know best how to interpret preliminary and not-validated flags.

SINCA region IDs

SINCA organises stations by administrative region using Roman-numeral codes. For the central Chile bounding box used in the case study (lat −38 to −32, lon −73.75 to −69.75), the relevant regions are:
Region IDRegion Name
VValparaíso
MMetropolitana de Santiago
VIO’Higgins
VIIMaule
XVIÑuble
VIIIBiobío
IXLa Araucanía

Data validation tiers

Each row in the SINCA hourly CSV has three value columns: validated, preliminary, and not_validated. The parser applies a strict preference order:
validated  →  preliminary  →  not_validated  →  no_data (NaN)
The resolved value and its status label ("validated", "preliminary", "not_validated", "no_data") are stored in the intermediate DataFrame. Only the resolved numeric value reaches the final (lat, lon, time)-indexed output.
Not-validated data have not undergone quality assurance review. Treat high concentration values from this tier with appropriate caution and consult the SINCA operator or local experts before using them in a peer-reviewed analysis.

Function reference

get_sinca_region_stations(region_id)

Lists all monitoring stations in a SINCA administrative region by scraping the region index page.
df_stations = get_sinca_region_stations('VIII')
# Returns a DataFrame with columns:
#   region_id, station_id, station_name, station_url
print(df_stations.head())

get_sinca_station_metadata(station_url)

Extracts latitude and longitude from the Google Maps JavaScript embedded in a station page.
meta = get_sinca_station_metadata(
    'https://sinca.mma.gob.cl/index.php/estacion/index/id/123'
)
# Returns: {'lat': -33.464142, 'lon': -70.660797}

F_get_SINCA_from_web

The main entry point. Drop-in replacement for F_get_OpenAQ_from_API. Signature:
F_get_SINCA_from_web(
    n_lon_min,            # float — western boundary
    n_lat_min,            # float — southern boundary
    n_lon_max,            # float — eastern boundary
    n_lat_max,            # float — northern boundary
    t_start,              # numpy.datetime64 or str — UTC start
    t_end,                # numpy.datetime64 or str — UTC end
    regions,              # str or list[str] — SINCA region ID(s)
    l_variables=['PM2.5'] # list[str] — currently only 'PM2.5' is supported
)
Returns: pandas.DataFrame with MultiIndex (lat, lon, time) and a PM2.5 column (µg/m³, UTC timestamps), or None if no data are found. Structurally identical to the output of F_get_OpenAQ_from_API.

Usage

Basic call — Chile central valley

f_data_monitors_SINCA = F_get_SINCA_from_web(
    n_lon_min=-73.75,
    n_lat_min=-38.0,
    n_lon_max=-69.75,
    n_lat_max=-32.0,
    t_start=np.datetime64('2022-12-01 00:00:00'),
    t_end=np.datetime64('2023-03-31 23:59:59'),
    regions=['V', 'M', 'VI', 'VII', 'XVI', 'VIII', 'IX'],
)

Inspecting station coverage before downloading

# List all stations in Biobío and inspect before querying data:
df_biobio = get_sinca_region_stations('VIII')
print(f'Found {len(df_biobio)} stations in VIII (Biobío)')
print(df_biobio[['station_name', 'station_url']].to_string())

Quality-filtering the returned data

After retrieving data, apply the same sign and upper-bound filter used in the case study:
# Accept hourly PM2.5 values between 0 and 2000 µg/m³:
f_data_monitors = f_data_monitors_SINCA.copy()
f_data_monitors['PM25_filtered'] = f_data_monitors['PM2.5'].where(
    (f_data_monitors['PM2.5'] > 0) & (f_data_monitors['PM2.5'] < 2000)
)

Comparing SINCA to OpenAQ at a single site

import matplotlib.pyplot as plt

# Parque O'Higgins monitor, Santiago:
n_lat, n_lon = -33.464142, -70.660797

fig, ax = plt.subplots(figsize=(15, 5))
ax.plot(
    f_data_monitors_OpenAQ.loc[(n_lat, n_lon)].index,
    f_data_monitors_OpenAQ.loc[(n_lat, n_lon)]['PM2.5'],
    color='blue', label='OpenAQ (24-h rolling avg)'
)
ax.plot(
    f_data_monitors_SINCA.loc[(n_lat, n_lon)].index,
    f_data_monitors_SINCA.loc[(n_lat, n_lon)]['PM2.5'],
    color='orange', label='SINCA (1-h avg)'
)
ax.set_ylabel('PM$_{2.5}$ [µg/m$^{3}$]')
ax.set_title("Parque O'Higgins — OpenAQ vs SINCA")
ax.legend()

Timezone handling

SINCA stores timestamps in Chilean local time (America/Santiago). F_get_SINCA_from_web converts to UTC automatically using pandas timezone-aware operations:
df["time"] = (
    df["datetime_local"]
    .dt.tz_localize("America/Santiago", ambiguous="NaT", nonexistent="NaT")
    .dt.tz_convert("UTC")
)
This ensures direct alignment with MERRA-2 CNN (UTC) and OpenAQ (UTC) timestamps without any manual offset arithmetic.

Internal scraping architecture

The diagram below shows how the four internal helpers chain together inside F_get_SINCA_from_web:
F_get_SINCA_from_web(regions, bbox, t_start, t_end)

  ├─ get_sinca_region_stations(region_id)
  │    └─ scrapes /index.php/region/index/id/{region_id}

  └─ for each station:
       ├─ get_sinca_station_metadata(station_url)
       │    └─ parses Google Maps LatLng from station HTML

       ├─ get_sinca_station_graph_links(station_url)
       │    └─ finds apub.htmlindico2.cgi links for PM25/horario

       ├─ get_sinca_macro_options(graph_url)
       │    └─ extracts 'macro' value from left frame of CGI page

       └─ _download_one_station_pm25(station_row, date_from, date_to)
            └─ GET apub.tsindico2.cgi → _parse_sinca_hourly(raw_text)
For the full implementation see the F_get_SINCA_from_web function reference.

Build docs developers (and LLMs) love