How-to guides

Complete a specific task with the public panel APIs

These recipes assume familiarity with the input panel. The executable examples use the same fixtures as the tutorials. In application code, replace those fixtures with the caller’s input panel.

Publish an anchored feed

  • Inputs: Supply a long panel, an exclusive UTC reading moment, the forecast source name and externally fitted parameters.
  • Parameter dates: The training window must end before the publication date.
  • Output selection: Request expected_surprise for a fraction relative to consensus. Request anchored_level separately when a level is needed.
import pandas as pd
import tutorial_support as examples
import postforecast as pf

examples.set_style()
estimates = examples.example_panel()
parameters = pf.AnchoringParameters.model_validate(
    pf.ANCHORING_2025_01.model_dump(mode="json")
)
feed = pf.publish_anchored(
    estimates,
    pd.Timestamp("2026-01-20", tz="UTC"),
    forecast_source="model",
    parameters=parameters,
    fields=("expected_surprise",),
)
feed[["entity", "period", "expected_surprise", "eligible", "eligibility_reason"]]
entity period expected_surprise eligible eligibility_reason
0 ZS 2026Q1 0.0329676 True publishable
  • Real parameters: Replace the tutorial’s shipped parameter payload with the approved artifact for the consuming application. File loading stays with the caller.
  • Explicit universe: Pass subjects= to retain requested subjects even when they have no known observations. Refused subjects keep a row and a reason.
  • Units: A surprise of 0.03 means 3%. Raw source levels are excluded from this publication API.
  • Reading policy: Publication uses the 30-day revision with a 60-day maximum age at each revision read. Use prepare_anchored_subjects and AnchoredEstimate when a different preparation policy is required.

Configure BayesianPosterior

Prepare the panel and apply the posterior with the same settings object. This recipe uses the plain profile; presets explains other choices.

history = examples.quarterly_history()
as_of = pd.Timestamp("2026-05-10", tz="UTC")
settings = pf.posterior_preset("plain-2026-09")
subjects = pf.prepare_bayesian_subjects(
    history, as_of, forecast_source="model", settings=settings,
)
fitted = pf.BayesianPosterior(forecast_source="model", settings=settings).fit(subjects)
predictions = fitted.apply(subjects)
predictions.tail(1)[["entity", "period", "posterior_level", "posterior_lower", "posterior_upper", "eligible"]]
entity period posterior_level posterior_lower posterior_upper eligible
8 ZS 2026-06 800.649 795.166 807.144 True
  • History: Keep earlier periods in the panel. Select the target output after preparation.
  • Replays: Prepare at each historical cutoff; do not reuse today’s prepared history.
  • Freshness: Use the prepared source-age columns for the application’s publication policy.
  • First releases: If required, retain only the earliest actual per subject before preparation.
  • Overrides: Use posterior_preset(name, version="application-v1", ...) for changed calculations, then prepare again with the new settings. See Bayesian settings.

Inspect refusals

Use eligible as the publication verdict and retain eligibility_reason for diagnosis. Do not substitute consensus or zero for a refused result.

missing_model = estimates.loc[estimates.source != "model"]
refused = pf.publish_anchored(
    missing_model,
    pd.Timestamp("2026-01-20", tz="UTC"),
    forecast_source="model",
    parameters=parameters,
    fields=("expected_surprise",),
)
refused.loc[~refused.eligible, ["entity", "period", "eligibility_reason"]]
entity period eligibility_reason
0 ZS 2026Q1 missing_input
  • Malformed panel: PanelError reports a contract violation; correct the input before calling again.
  • Anchored refusal: Requested numeric outputs are missing and the subject remains in the result. See Anchored eligibility.
  • Bayesian refusal: Posterior outputs are missing, while prepared input columns remain. See Bayesian eligibility.
  • Short model history: Missing model precision alone still permits a prior-consensus posterior and interval; model precision and weight remain missing.

Retain an audit record

Store the complete parameter or settings payload alongside the output. A version identifier alone cannot reconstruct the calculation.

parameter_record = parameters.model_dump(mode="json")
settings_record = settings.model_dump(mode="json")
posterior_record = fitted.to_dict()
parameter_record
{'customary_beat': 0.0112,
 'gap_weight': 0.129,
 'revision_weight': 1.28,
 'maximum_absolute_gap': 0.25,
 'maximum_prediction_age': 'P21D',
 'maximum_consensus_age': 'P60D',
 'version': 'anchoring-2025-01',
 'fitted_through': '2024-12-31'}
  • Inputs: Retain the input snapshot or its reproducible identifier, the reading moment and the source identifiers in the consuming application.
  • Parameters: Keep the full payload, its version and fitted-through date when applicable. Settings chosen rather than fitted have no fitted-through date.
  • Software: Record the installed package revision alongside the run.
  • Outputs: Preserve subject keys, method, version and refusal status when combining results across sources or parameter sets.
  • Persistence: The caller writes the record; the library performs no file or network I/O.