BaseGenerator exists for that: subclass it, implement one method, and
your generator inherits timestamp handling, reproducible seeding,
parallel generation, pattern injection (changepoints, anomalies,
missingness), exogenous variables, and every dataframe backend.
This guide builds a small logistic-growth (“S-curve”) generator, a shape
none of the built-ins produce directly.
The contract A generator needs three things:Everything else is inherited.
- Subclass
BaseGenerator.- Declare its parameters as Pydantic
Fieldattributes.- Implement
generate_single_series(self, length: int) -> np.ndarray, returning one series of the requested length. Draw randomness fromself.rngso seeding and parallel generation stay deterministic.
What you implement, and what you get
generate_single_series is the only required method. It receives a
target length — which varies per series between min_length and
max_length — and returns a plain NumPy array. The base class attaches
timestamps derived from freq, assigns the unique_id/ds/y
columns, applies any requested pattern injection, and materializes the
result in the chosen dataframe backend. The generator is a Pydantic
model, so the shared parameters (min_length, freq, seed, engine,
and the injection controls) are available without redeclaring them.
Generate a panel

Pattern injection is inherited
Because changepoint, anomaly, and missingness injection live inBaseGenerator, they work on the custom generator with no extra code:
enabling them is a matter of setting the same parameters the built-in
generators use. Below the S-curve is generated with injected spikes and
dips and a level changepoint, and the ground-truth anomaly_flag column
is requested through ExogenousConfig so the injected points can be
marked.

Draw fromself.rng, notnp.randomself.rngis a seeded NumPyGenerator. Using it is what lets a fixedseedreproduce identical output and keeps parallel generation deterministic. Each series is generated with its own derived RNG state, so series differ from one another while the whole panel stays reproducible.
Contributing a generator back
To ship a generator as part of SynForecast rather than defining it inline, follow the same layout as the built-ins:- Add the module under
synforecast/generators/. - Export the class from
synforecast/generators/__init__.py. - Add tests under
tests/, and a page undernbs/docs/generators/<category>/.
Related
- Changepoints, anomalies, and missingness — the injection this generator inherits.
- Exogenous variables — datetime features, correlated regressors, and the ground-truth flags used above.
- Compose a dataset — combine your generator with others in
a
SynSet.

