Генератор pattern
Когда пригодится: у сигнала есть форма, которую не описать формулой — спрос по часам, демографическая волна, скриншот биржевого графика, любая «извилистая» линия. Вы рисуете картинку, а её форма растягивается на все строки: горизонтальная ось — номер строки (от первой до последней), вертикальная — значение. Рисунок может быть крошечным, строк — миллионы.
Никакой файл заранее не готовится. Картинка читается в момент запуска, и каждая строка сама вычисляет свою точку на ней, поэтому миллион строк стоит не больше памяти, чем десяток.
Примеры вывода ниже — иллюстративные, по версиям ядра числа могут чуть отличаться; гарантируется форма.
Зачем рисовать форму, а не брать распределение из списка
У готовых распределений (normal, poisson, …) форма фиксированная — колокол,
затухающий хвост. Настоящему сигналу часто нужна форма, которой в этом списке нет:
два горба, где правый выше, плато со всплеском в конце, спрос, который растёт к
полудню и падает ночью. «Два горба разной высоты» из normal не получить. pattern
снимает это ограничение: силуэт вы рисуете сами, и он ложится на строки как есть.
Как включить
Каждый <gen> с type="pattern" берёт ровно один
источник формы. Обычный источник — файл: рисуете в любом редакторе или делаете
скриншот графика и отдаёте его генератору:
<!-- ваш рисунок: SVG или PNG -->
<gen type="pattern" src="chart.svg" y_range="0..40"/>
Если форма достаточно простая, чтобы набрать её руками, тот же генератор принимает
точки прямо в конфиге — одна линия через points или полоса через upper / lower:
<gen type="pattern" points="0,5 20,40 40,8 60,45 80,15 100,5" y_range="0..40"/>
<gen type="pattern" upper="0,20 50,40 100,20" lower="0,5 50,10 100,5" y_range="0..40"/>
| Атрибут | Что задаёт |
|---|---|
src | Файл SVG или PNG — обычный способ задать форму |
points | Пары x,y прямо в конфиге вместо файла: x — по ширине, y — высота |
upper / lower | Две границы прямо в конфиге — коридор |
mode | signal (по умолчанию) — траектория; density — распределение |
y_range | Обязателен. min..max — чем становятся пол и потолок холста рисунка |
fit | низ..верх — куда ложится рисунок из src (ниже) |
interp | linear (по умолчанию) / smooth / step — поведение линии между точками |
spread | Разброс: каждая строка ±N в единицах y_range (по умолчанию 0 — точная линия) |
ink_threshold | 0..1 — насколько тёмным должен быть пиксель PNG, чтобы считаться чернилами (по умолчанию 0.5) |
decimals | Знаков после запятой (по умолчанию 0) |
src — картинка и есть конфиг
Читаются два формата, и оба внутри превращаются в одно и то же — векторный контур:
- SVG — читается по настоящей геометрии:
<path>,<polyline>,<polygon>,<line>,<rect>(скруглённые углы включительно),<circle>,<ellipse>. Кривые Безье и дуги проходятся так, как нарисованы, аtransformна фигуре или на любой объемлющей<g>применяется. Рисуйте в Illustrator, Figma, Inkscape или руками — экспортируйте и работайте. Фигуры различает одно правило: когда читается одиночная линия, примитивы (rect,circle,ellipse) считаются мебелью — рамкой и фоном экспортированного графика — и всё действительно нарисованное важнее их; в коридоре считается каждая фигура, потому что рисунок и есть область. - PNG с прозрачным фоном — нарисованные пиксели и есть форма, прозрачность —
пустота. Именно так выглядит обрезанный по графику скриншот или мазок кистью из
любого растрового редактора. Если у PNG сплошной фон, включается запасное правило:
чернила — тёмные пиксели, светлые — фон, а порог двигает
ink_threshold.
Ось y в SVG растёт вниз — так её хранит любая программа для рисования. TDC
переворачивает её, поэтому «выше на экране» всегда означает «больше значение».
Целый пример, от начала до конца
Вот настоящий файл — 240×140 пикселей, штрих на прозрачном фоне и больше ничего. Ни осей, ни подписей, ни рамки: всё непрозрачное в файле читается как часть рисунка.

<gen type="pattern" src="line-input.png" y_range="0..100"/>
Прогоняем на 40 строк и накладываем результат на рисунок. Зелёные точки — это сгенерированные значения, оранжевая линия — картинка:
- линия, нарисованная в файле
- сгенерированные значения (40 строк)
В картинке 240 пикселей ширины, а в прогоне 40 строк, и эти числа никак не связаны: просите 40 строк или 4 000 000 — тот же рисунок растянется на них.
То же самое из векторного файла
SVG не аппроксимируется. Вот файл с одной кубической кривой Безье внутри <g>,
который переворачивает ось y, — две вещи, которые редакторы выдают постоянно:
- кривая Безье из файла, с применённым transform
- сгенерированные значения (40 строк)
Рисунок читается по столбцам
TDC никогда не гадает, что у вас на картинке — «одна линия» или «полоса». Он измеряет, и измерение само отвечает на этот вопрос.
Для каждого столбца рисунка берутся два замера: сверху вниз до первой встреченной отметки и снизу вверх до первой встреченной отметки.
- Aзамеры сошлись в одном пикселе — значение точное
- Bзамеры разошлись — значение случайное между ними
- сами замеры: сверху вниз и снизу вверх
- Оба замера пришли в одну и ту же точку → этот столбец даёт точное значение на графике. Все строки, попавшие сюда, получат его без всякой случайности.
- Замеры разошлись → этот столбец — полоса. Строка получит случайное значение
между двумя краями, зафиксированное
seed.
Поэтому картинка из двух штрихов — это коридор, и каждая строка берёт случайное значение между ними. Вот входной файл и 300 строк, сгенерированных по нему:

- полоса, нарисованная в файле
- сгенерированные значения (300 строк)
- Aодин столбец: значение берётся между его краями
Два следствия, которые стоит знать:
- Одна картинка может быть и тем и другим. Линия, которая сначала идёт одна, а потом раздваивается, до развилки даёт точные значения, а после — случайные. Ни атрибута, ни выбора режима не нужно.
- Всё замкнутое — это коридор. Нарисуйте машину, лист, кляксу: у неё есть верхний край и нижний, значит она читается как полоса между ними. Это не фигура речи — вот машина:

- нарисованная машина
- сгенерированные значения (300 строк)
- Aколесо опускает нижний край кузова
- Bземля до и после машины — одна линия, значения точные
Вот линия, которая идёт ровно, а потом раздваивается — одна ветка вверх, другая вниз:

- линии из файла
- сгенерированные значения (60 строк)
- Aздесь линия раздваивается
- Bдо развилки — одно и то же точное значение
- Cпосле — случайное внутри расходящейся полосы
Тот же прогон на двух разных сидах показывает это в лоб — первая половина одинаковая, вторая нет:
seed A: 50 50 50 50 50 50 44 47 66 18 45 seed B: 50 50 50 50 50 51 57 61 60 81 35
Коридор прямо в конфиге: два атрибута, а не одна строка
Коридору, нарисованному в файле, атрибуты вообще не нужны — два штриха на картинке
уже читаются как две границы. Набранному прямо в конфиге нужны два атрибута,
upper и lower, по одной кривой в каждом:
<gen type="pattern" upper="0,80 100,80" lower="0,20 100,20" y_range="0..100"/>
Соблазнительное сокращение — один points с разделителем между двумя линиями —
не существует, и ; не проглатывается, а получает отказ:
error[TDC285]: pattern: ";" does not separate two lines in points= — every number is read as one curve. For a band, draw the two edges separately: upper="0,80 100,80" lower="0,20 100,20".
Та же проверка ловит рисунок нулевой ширины — все точки на одном x:
error[TDC285]: pattern: every point sits at x=50, so the drawing has no width and a card has nothing to read across. Give the points at least two different x coordinates.
Оба отказа выдаёт и check, и прогон: points, upper и
lower читаются до первой карточки тем же кодом, что и в прогоне.
y_range — масштаб, и он обязателен
У рисунка нет собственного масштаба. Одна и та же кривая выходит из одного
редактора в координатах 0..100, из другого — 0..480, из третьего — 0..10002345345, и
ни одно из этих чисел ничего не значит, пока вы не скажете, что такое ось.
y_range="min..max" — это и есть такое утверждение, поэтому атрибут обязательный, а не
необязательный: без него любой ответ был бы догадкой о чужих настройках экспорта.
Масштабируется холст, а не чернила:
| откуда рисунок | пол холста | потолок холста |
|---|---|---|
| PNG | низ изображения | верх изображения |
| векторный файл (SVG) | самая нижняя точка самого рисунка | самая верхняя точка самого рисунка |
points / upper / lower | 0, растёт вниз, если вы рисовали ниже | 100, растёт вверх, если вы рисовали выше |
Для рисунка из точек холст — это процентная доска: по умолчанию 0..100, и она только растёт, чтобы вместить нарисованное снаружи, но никогда не сжимается. Именно это делает горизонтальную линию на 50 серединой любого запрошенного диапазона. Мерь мы по чернилам — та же линия была бы самым высоким, что есть, а значит потолком.
Три строки разные, потому что три источника несут разное. PNG ровно такой высоты, какой
себя объявляет, — его рамка настоящий холст, и пустое место над штрихом честно опускает
его значения. У векторного файла рамки, которой стоило бы верить, нет: большинство
редакторов при экспорте обрезают viewBox по рисунку, а обрезанный не отличить от
намеренно тесного. Поэтому меряется сам рисунок, а поставить его на место —
дело fit.
<gen type="pattern" points="0,0 50,100 100,0" y_range="0..40" decimals="1"/>
<gen type="pattern" points="0,0 50,100 100,0" y_range="-2..2" decimals="1"/>
0..40 0.0 8.0 16.0 24.0 32.0 40.0 32.0 24.0 16.0 8.0 0.0 -2..2 -2.0 -1.2 -0.4 0.4 1.2 2.0 1.2 0.4 -0.4 -1.2 -2.0
За диапазон не выходит ничего, в каких бы координатах вы ни рисовали. Сочетайте с
decimals, когда нужны непрерывные значения, а не целые.
- один и тот же нарисованный треугольник
- сгенерированные значения (25 строк)
y_range всегда означает диапазон значений, которые вы получите. В режиме
mode="density" ось значений — это ширина рисунка, а не высота, поэтому там
диапазон растягивается по картинке слева направо: смысл атрибута тот же, меняется
только ось.
fit — куда ложится рисунок из файла
Рисунок несёт форму. Положение он несёт только вместе с доской — а файл, выгруженный из чужого редактора, доски не несёт. Ни единиц, ни начала координат, ни даже того, где верх. Измерить у него можно ровно две вещи: его собственную нижнюю точку и его собственную верхнюю.
fit="низ..верх" говорит, чем эти две станут.
<gen type="pattern" src="foreign.svg" y_range="200..300" fit="255..297"/>
Нижняя точка рисунка выйдет как 255, верхняя — как 297, и ничто между ними за эту
полосу не выйдет, в каких бы координатах файл ни рисовали — 0..1000 или -5..3e6.
Форма сохраняется, а положение — то, которое вы объявили.
Не пишите fit — и рисунок займёт весь y_range: низ на пол, верх на потолок. Это
не догадка, а объявленное соглашение: оно ничего не выдумывает.
| холст (что отображается) | без fit | с fit | |
|---|---|---|---|
| векторный файл | сам рисунок | занимает весь y_range | его края ложатся на полосу |
| PNG | рамка изображения | рамка занимает весь y_range | рамка ложится на полосу |
При mode="density" он идёт за той же осью, что и y_range. Там ось значений — это
ширина рисунка, а не высота, поэтому fit кладёт его левый и правый край, а не низ и
верх. fit — это просто более узкий y_range для рисунка из src: ось он меняет ровно
там, где её меняет y_range, и никогда отдельно.
Рядом с points / upper / lower атрибут отклоняется
(TDC300). Набранная точка — это уже процент доски 0..100:
80 означает 80% от y_range, размещать больше нечего, и написать оба сразу значило бы
сказать в конфиге две вещи одновременно.
Коридору из файла он нужен
Два штриха в одном файле — это коридор, а полоса, измеренная относительно самой себя,
всегда полная. Поэтому без fit полосатый SVG заполняет весь y_range — по правилу
выше это верно и почти никогда не то, чего хотели. fit несёт в конфиге ровно то, что
набранная запись несёт в своих числах:
<gen type="pattern" upper="0,80 100,80" lower="0,60 100,60" y_range="0..100" decimals="1"/>
<gen type="pattern" src="band.svg" y_range="0..100" fit="60..80" decimals="1"/>
набран 62.3 62.5 73.4 76.0 71.7 75.0 61.3 64.3 нарисован 62.3 62.5 73.4 76.0 71.7 75.0 61.3 64.3
Цифра в цифру — и так во всех пяти реализациях: эта пара лежит в общих фикстурах.
В SVG ось y растёт вниз: верх файла — это y=0. Движок её переворачивает, поэтому
то, что выше в вашем редакторе, выходит больше в данных. Записывать это нигде не нужно —
но полезно знать, когда рисунок вышел вверх ногами и вы полезли смотреть файл.
decimals — знаки после запятой
decimals задаёт, сколько дробных знаков остаётся у значения (по умолчанию 0, то
есть целые). Пригодится, когда кривая кормит цену, температуру или любую измеряемую
величину, где округление до целых сплющит форму.
<gen type="pattern" points="0,0 50,100 100,0" y_range="-1..1" decimals="2"/>
-1.00 -0.60 -0.20 0.20 0.60 1.00 0.60 0.20 -0.20 -0.60 -1.00
Средняя строка стоит на вершине и даёт 1.00 — потому что там её линия и пересекает
рисунок. Ниже,
в Растягивании,
это правило разобрано целиком.
Растягивание — точек на рисунке почти никогда не столько, сколько строк
Строка i из count читает рисунок в точке t = i / (count − 1), и её значение —
это пересечение её собственной вертикали с нарисованной линией. Десять строк — это
десять пересечений, их можно проверить на картинке линейкой. Никакого второго правила
под этим нет.
Деталей на рисунке больше, чем строк → вы получаете пересечения, а не сводку. Пила из пяти зубцов, ужатая в пять строк, выдаёт те пять мест, куда эти строки попали, и каждое из них — настоящая точка пилы:
<gen type="pattern" points="0,0 10,100 20,0 30,100 40,0 50,100 60,0 70,100 80,0 90,100 100,0"
y_range="0..100"/>
0 50 100 50 0
Расширьте тот же прогон до 40 строк — и зубцы пройдут целиком, потому что теперь строки
идут достаточно часто, чтобы попадать на них: 0 26 51 77 97 72 46 21 5 31 56 82 …
Не попасть в пик, который лежит между двумя строками, — это не потеря замера, а то, что и означает «пять строк». Рисуйте подробнее или просите больше строк: на миллионе строк тот же рисунок распишется целиком, со всеми пиками. Смысл правила в том, что вы можете посмотреть на свой рисунок заранее и сказать, что получится.
- нарисованная пила
- сгенерированные значения
- A300 строк — зубцы проходят целиком
- B7 строк — семь пересечений, остальное между ними
Строк больше, чем точек → интерполяция, и вот тут в дело вступает interp.
interp — как ведёт себя линия между двумя точками
Между двумя далеко отстоящими точками может уместиться несколько тысяч строк. Сам по
себе прямой отрезок растёт ровно на одну и ту же величину каждую строку —
математически верно и заметно искусственно. interp выбирает поведение:
| Значение | Что делает |
|---|---|
linear (по умолчанию) | Прямые отрезки — постоянная скорость между двумя точками |
smooth | Кривая через точки с плавным входом и выходом, без вылетов |
step | Держит значение точки до следующей — лесенка |
smooth использует монотонную кубическую кривую: она скругляет углы и меняет
скорость, но никогда не уводит линию выше или ниже реально нарисованных значений — из
изгиба не появится фантомный пик. Тот же рисунок из трёх точек на 11 строк:
linear: 0 8 16 24 32 40 52 64 76 88 100 smooth: 0 8 15 23 31 40 50 62 75 88 100 step: 0 0 0 0 0 40 40 40 40 40 100
Обратите внимание, чем заканчивается step. Лесенка держит значение точки в полосе
справа от неё, а у последней точки такой полосы нет — рисунок там кончается.
Поэтому последняя точка читается там, куда попадает любой прогон: на самом правом
краю, где его пересекает линия последней строки. Все три способа сходятся там на
последнем, что вы нарисовали.
На рисунке с настоящими изломами разница видна сразу — пунктир это то, что нарисовано, точки это то, что вышло:
- что нарисовано: ломаная через пять точек
- сгенерированные значения (41 строка)
Посмотрите на шаги: у linear повторяется 8, 8, 8, 8 — идеально предсказуемо. У
smooth идёт 8, 7, 8, 8, 9, 10, 12, 13 — линия мягко отходит от точки, разгоняется
и мягко приходит.
spread — превратить одну линию в туннель
spread="N" разбрасывает каждую строку на ±N в единицах вашего y_range. По
умолчанию 0: линия точная и на 100% предсказуемая. Задайте значение — и
нарисованная линия становится центром полосы, так что рисовать оба края коридора
ради небольшого дрожания уже не нужно.
Разброс следует объявленному масштабу: при y_range="0..100" spread="1" — это один
пункт шума, а при y_range="0..1" тот же относительный эффект даст spread="0.001".
<gen type="pattern" src="ramp.svg" y_range="0..100" spread="5"/>
spread 0, seed A: 0 10 20 30 40 50 60 70 80 90 100 spread 5, seed A: 5 13 16 29 37 52 57 69 83 86 99 spread 5, seed B: 5 11 21 26 45 53 64 73 82 94 99
Тот же одиночный штрих из line-input.png, но уже со spread="6":
- нарисованная линия — центр
- коридор ±6, который вы не рисовали
- сгенерированные значения (60 строк)
Тренд не тронут, просто каждая строка садится куда-то в пределах ±5 от него. Как и у
коридора, разброс детерминирован: тот же сид воспроизводит его точь-в-точь.
spread работает и поверх рисунка, который уже является полосой, — расширяет её на
N в обе стороны.
ink_threshold — порог «тёмный/светлый» для PNG
Когда у PNG сплошной фон, чернила определяются темнотой. ink_threshold — это порог
по шкале 0..1 (по умолчанию 0.5): пиксель считается чернилами, если он не светлее
порога. Поэтому поднимайте к 1, чтобы забрать бледные сглаженные края и светло-серое,
и опускайте к 0, чтобы оставить только почти чёрные штрихи. На PNG, нарисованном на
прозрачности, порог не влияет ни на что: там альфа-канал уже говорит, что нарисовано.
<gen type="pattern" src="faint-curve.png" ink_threshold="0.8" y_range="0..100"/>
В этом файле два штриха на белом холсте — чёрный и светло-серый, — и порог решает, существует ли серый:

- чёрный штрих
- светло-серый штрих
- сгенерированные значения (60 строк)
Сигнал — это траектория, а не гистограмма
Значение строки — это высота кривой в её позиции по порядку. То есть числа выходят вдоль кривой, как след пера: это траектория, а не «куча значений». Если взять те же числа и, забыв про порядок, построить гистограмму (как часто встречается каждое значение), форма кривой в ней не проявится. Вот настоящая гистограмма рисунка из двух горбов на 300 строках:
0 | ################################## 29 3 | ######################################## 34 7 | ######################################## 34 10 | #################################### 31 13 | ######################### 21 17 | ########################## 22 20 | ################################# 28 23 | ########################## 22 27 | ######################### 21 30 | ################################## 29 33 | ################### 16 37 | ############### 13
Никаких двух горбов — гистограмма почти ровная. Это не баг: сигнал проходит через
каждую высоту примерно одинаково часто, поэтому куча его значений не похожа на
рисунок. Если нужно, чтобы рисунок задавал частоту, — это второе прочтение,
mode="density", о нём ниже.
mode — два вопроса, которые можно задать рисунку
Одна и та же картинка отвечает на два разных вопроса, mode выбирает какой:
| Режим | Вопрос | Что выходит |
|---|---|---|
signal (по умолчанию) | «какое значение получит эта строка?» | 0, 20, 40, 70, 90, 100, 90, 70, 40, 20, 0 — идём по линии, по порядку |
density | «как часто встречается это значение?» | куча чисел, сгущённая там, где нарисован горб, в случайном порядке |
В density оси меняются смыслом: по горизонтали — значение, а высота кривой —
как часто оно встречается. Нарисовал горб посередине — большинство чисел упадёт в
середину; нарисовал два горба разной высоты — тот, что выше, заберёт пропорционально
больше. По сути «нарисуй свою вероятность» вместо выбора normal / poisson из
списка.
<!-- треугольник, стоящий между x=25 и x=75 -->
<gen type="pattern" points="0,0 25,0 50,100 75,0 100,0" y_range="0..100" mode="density"/>
0- 9 | 10-19 | 20-29 | ## 85 30-39 | ########################### 901 40-49 | ########################################################## 1911 50-59 | ############################################################ 1955 60-69 | ############################## 978 70-79 | ##### 170 80-89 | 90-99 |
Сами значения выходят вперемешку — 60 57 36 49 48 40 67 53 …, — потому что у
распределения нет порядка. И за пределами 25..75 не появляется ничего: там рисунок
плоский, а плоско — значит «никогда».
То же самое, но картинкой вместо набранных руками точек. Вот горб, нарисованный заливкой:

<gen type="pattern" src="hump-input.png" y_range="0..100" mode="density"/>
Генерируем по нему 6000 строк и считаем, как часто выпало каждое значение:
- Aчто нарисовано в файле
- Bгистограмма 6000 сгенерированных значений
- Cвысота рисунка здесь = как часто выпадает это значение
В этом вся идея: силуэт, который вы намазали кистью, становится гистограммой данных. Никакой формулы нигде не выбиралось.
Причём высота работает пропорционально, а не просто «тут есть, тут нет»: нарисуйте один горб вдвое выше другого — он заберёт примерно вдвое больше значений:
- Aчто нарисовано: два горба разной высоты
- Bгистограмма 6000 сгенерированных значений
- Cлевый горб
- Dправый, вдвое выше — и значений вдвое больше
Что стоит знать про density:
- Ноль — это пол картинки. У PNG это нижний край изображения, у SVG и точек в конфиге — самая низкая точка рисунка. Где кривая ниже всего, то значение не выпадает никогда, — поэтому доводите кривую до основания по краям нужного диапазона.
- От полосы берётся верхний край. Если нарисован коридор, форму распределения задаёт его контур.
interpработает и здесь — и он реально двигает вес.smoothдаёт скруглённое распределение вместо угловатого, но если рисунок — это СТОЛБЧАТАЯ диаграмма, по одной объявленной доле на столбик, беритеinterp="step". Только он держит значение по всей ширине столбика;linearиsmoothпроводят линию ЧЕРЕЗ точку, и пик растекается на соседей. Померено на десяти столбиках, 200 000 строк, пик объявлен 40%:stepоставил два центральных столбика на 28.4% и 27.9%,smoothсобрал их в 41.5% и 10.0%. Те же точки — другие доли, выбор не косметический.spreadздесь запрещён. Рисунок и так задаёт разброс, так что сочетание этих двух вещей — ошибка, а не возможность.- Плоский рисунок означает «мне всё равно» и даёт равномерный разброс по диапазону, а не ошибку.
- Детерминированно и потоково, как и всё остальное: тот же сид воспроизводит ту же кучу на любом количестве строк.
Детали
- Детерминированность: там, где рисунок — одиночная линия, значение строки просто
равно высоте в этой точке (никакой случайности вообще); там, где полоса, — или там,
где задан
spread, — разброс зафиксированseed. Тот же сид и конфиг → тот же результат. - Любой объём, любой движок: каждая строка считается из своего номера, память не растёт. Миллион строк из маленького рисунка спокойно едет на потоковых движках.
- Файл читается один раз, в начале прогона, и превращается в геометрию — стоимость не зависит от количества строк.
Проверить руками
Несколько однострочников для интуиции:
points="0,0 50,100 100,0" y_range="0..100"— треугольник: значения растут к середине и падают.points="0,10 90,10 100,100" y_range="0..100"— ровная линия со всплеском только в последних 10% строк.upper="0,0 50,40 100,0" y_range="0..100"— полоса: случайное от0до центрального пика.src="chart.png" y_range="0..100"— нарисованная форма становится данными вдоль контура.- добавьте к любому из них
spread="2"— та же форма, но с дрожанием. - а с
mode="density"та же форма начинает решать, как часто выпадает каждое значение.
Случай со всплеском лучше всего показывает идею «позиция = номер строки»:
строки 1–18: 10 (ровный участок) строка 19: 53 (подъём) строка 20: 100 (всплеск)
Фронтенд-рисовалка, которая экспортирует ровно такие SVG/PNG, — чтобы набрасывать кривую мышью, а не открывать редактор.
См. также
- Временные ряды — когда форма это тренд + сезон + шум.
- Number — для диапазонов и простых случайных целых.
- Детерминизм и пропорции — как
seedфиксирует разброс. - Большие объёмы и потоковая генерация — миллионы строк из одного маленького рисунка.