Publishing a Climate Table from a Parsed Array

After parsing climate HTML, publishing a table still needs month indexes, missing-month handling, unit labels, and a validation checklist that CSS cannot replace.

Back to PHP weather scripts and software guides

Extracting numbers from Weather Display’s climatedatayearout.html only produces an array. The historical URL /scripts/climate1/script.php was the next step: print that array as a table, optionally as CSV. Wayback captures of this path had already collapsed into a domain-expiry notice. The useful remainder is the publication problem. Indexing, missing months, and unit labels are data. CSS is not.

Climate1 covers why the HTML source is fragile. Climate2 covers a different WD file and what to do when two parsers disagree. This page is the wiring of a derived table after a parse has already been attempted.

The array is an index, not a spreadsheet

A climate-year structure that is safe to publish looks like a map from a month index to named elements, plus an annual record, plus metadata:

  • year as a four-digit calendar year (or an explicit water year, never both unlabeled);
  • units per element, not a single global “imperial”;
  • months[1..12] (or [0..11] if you must, but then document the origin);
  • missing as a first-class state, distinct from zero;
  • source_file and parsed_at so a later reader knows which HTML build you used.

The historical TNET sample printed “the output array” so an operator could see keys. That instinct was right. A table that cannot be addressed as months[7].rain_total is a screenshot in HTML form.

Off-by-one errors show up immediately. If WD’s January is column 1 in the file and PHP arrays default to 0, July’s rain lands on June. Graphs then show a one-month phase shift that looks like climate. Fix indexing in the data structure, not with a CSS nth-child offset.

Missing months are data

A year file generated in August does not contain autumn. WD often filled unused cells with dashes, empty strings, or  . Publication rules:

  • Do not convert those cells to 0. Zero January snow in Phoenix can be real; zero November rain printed in August is a future month.
  • Do not drop the month from the table. A twelve-row skeleton with an explicit empty state is easier to audit than a seven-row table that looks complete.
  • Do not interpolate. Filling October from a climatology would be a scenario, not an observation and not WD’s derived monthly value.
  • For annual totals, say whether they are year-to-date or a completed year. A YTD annual column next to empty months is consistent; a “year” mean of eight months labeled as twelve is not.

Official monthly products from NCEI document how they handle incomplete periods in GSOM/GSOY (documentation PDF). A station table will not match those rules, but it should have a rule and print it once above the grid.

Unit labels live in the cells’ metadata

Putting °F only in a CSS ::after on th.temp looks clean and dies at the first unit change. When the operator switches WD to Celsius, the stylesheet still paints Fahrenheit. Put the unit on the element in the array and render it as text in the header or in every cell group.

Elements that commonly lose their units in WD HTML skins:

  • temperature versus dewpoint versus wet-bulb (all degrees, not always the same code path);
  • rain versus snow versus water equivalent;
  • pressure (inches of mercury versus hectopascals);
  • wind (mph, knots, km/h, m/s);
  • sunshine hours versus solar energy.

A published table should not require the reader to remember the station’s setup screen. CSV export is the test: if the CSV header is max_temp with no unit, the table is incomplete even if the web page looks labeled.

CSS presents; it does not validate

The historical scripts emphasized stylesheet tags so the table could be “prettied up.” Color, zebra striping, and responsive overflow are presentation. They cannot encode:

  • which values failed a range check;
  • which months are incomplete;
  • which cells the parser could not bind to a header.

If you highlight extremes, define the rule in data (is_monthly_extreme: true) and let CSS read a class. Do not scan painted colors later as if they were quality flags. Do not use red font as the only record that a value is missing.

Accessibility follows the same split. A <table> with <th scope="col"> and a caption stating year, station, and units is a data table. A pile of <div>s styled as a grid is not, even if it matches the old WD skin.

Validation checklist for a climate HTML parser

Run this list on every new WD build, not once.

  1. Fixture identity. The input file’s year, station title, and filename match the metadata you will print.
  2. Header bind. Every statistic name you care about is mapped by label, not by column index alone. If you must use indexes, assert the header row text in the test.
  3. Month cardinality. Twelve month keys. No thirteenth ghost column from a trailing delimiter.
  4. Missing-token set. Document the exact strings WD uses for unused cells (-----, empty, &nbsp;, --) and map them all to missing.
  5. Numeric parse. Thousand separators, leading plus signs on “departure from average,” and T for trace. Trace is not float zero (NWS NOWData).
  6. Round trip. Annual rain versus sum of monthly rain within a stated rounding tolerance. Mean between min and max where those exist.
  7. Unit invariance. Changing a fixture’s unit labels without changing numbers must change metadata, not silently keep the old unit string.
  8. Encoding. Degree signs and dashes survive UTF-8. Mojibake in a month name is a failed parse.
  9. Non-operational markup. Comments, scripts, and WD leftover HTML do not become cells.
  10. Golden file. Store a sanitized fixture and the expected array. When WD changes layout, the test fails before the public table lies. Run that comparison in a private harness, not on a public /test/ URL.

If step 10 is missing, you will learn about layout changes from a viewer who noticed that July is blank.

CSV is a publication format too

The old script.php offered ?dwnld=1 for a comma-delimited file. That is a reasonable extra view if:

  • the delimiter and quoting are actual CSV (commas inside station names are quoted);
  • missing values have a token, not an empty field that spreads columns;
  • the download is generated from the same array as the HTML table, not from a second parser.

A download URL that re-parses live HTML on each click doubles the fragility. Parse once, store the array, publish many views.

What not to ship

Do not paste recovered PHP from Wayback. Do not treat a CC license footer on a 2000s sample page as covering a new implementation. Do not rehost script.txt. Describe the workflow; point operators to current Weather Display exports and to the scripts index.

TNET keeps this URL as an explainer in the legacy scripts collection. The modern research analogue is not a climate table; it is the requirement that derived summaries stay labeled as derived and that source files remain inspectable. That is why the next reading is still data sources, quality controls, and methodology if you are documenting a pipeline rather than skinning a grid.