phiz

Guides

Data and fields

Data inputs

Plot::of() and each geom’s data: argument accept data in several shapes:

  • a list of row arrays, such as [['x' => 1, 'y' => 2], ...]
  • an array of equal-length columns, such as ['x' => [1, 2], 'y' => [2, 3]]
  • a phibble table, or any object with toRows() or toColumns()
  • a Laravel Collection, or any object with toArray()
  • any iterable of rows, where rows may be arrays or objects
  • Data::url('cars.csv'), which Vega-Lite fetches in the browser
  • Data::named('live'), a data source the page supplies at runtime

Inline data is embedded in the specification. Values are made safe for JSON: DateTimeInterface values become ISO 8601 strings, enums become their values, and NAN and INF become null, which Vega-Lite treats as missing.

use Phiz\Plot;

$columns = [
    'month' => ['2026-01-01', '2026-02-01', '2026-03-01', '2026-04-01', '2026-05-01', '2026-06-01'],
    'visits' => [1200, 1350, 1290, 1610, 1820, 1765],
];

$plot = Plot::of($columns)
    ->aes(x: 'month', y: 'visits')
    ->line()
    ->point(size: 50);

Field types

Vega-Lite needs a measurement type for every mapped field. phiz infers it from inline data:

  • quantitative, when every non-null value is an integer or a float
  • temporal, when every value is an ISO date or date-time string
  • nominal, otherwise

A numeric code such as a cylinder count is quantitative by this rule. It gets a continuous color scale and gradient legend unless you mark it as categorical. Field shorthand sets the type explicitly with a suffix: :Q (quantitative), :N (nominal), :O (ordinal), or :T (temporal). factor('cyl') is the equivalent of R’s factor(cyl), and its levels: argument sets the order.

use Phiz\Datasets;
use Phiz\Plot;

use function Phiz\factor;

$plot = Plot::of(Datasets::mtcars())
    ->aes(x: 'wt', y: 'mpg', color: factor('cyl'), shape: 'am:N')
    ->point(size: 60)
    ->labs(color: 'Cylinders', shape: 'Manual');

URL data cannot be inspected in PHP, so phiz assumes quantitative positions and nominal groupings. Use shorthand types for anything else.

Aggregates and time units

Shorthand also covers Vega-Lite’s aggregates and time units: 'mean(hwy)', 'count()', 'median(price)', 'year(date):O', and 'yearmonth(date)'. The aggregation runs in Vega-Lite, grouped by the other mapped fields.

use Phiz\Datasets;
use Phiz\Plot;

$plot = Plot::of(Datasets::economics())
    ->aes(x: 'year(date):O', y: 'mean(psavert)')
    ->col(fill: '#4C78A8')
    ->labs(x: null, y: 'Mean personal savings rate (%)');

Computed fields

calc() maps an aesthetic to a field computed from a Vega expression. The expression refers to the row as datum.

use Phiz\Datasets;
use Phiz\Plot;

use function Phiz\calc;

$plot = Plot::of(Datasets::mpg())
    ->aes(x: 'cty', y: calc('datum.hwy - datum.cty', as: 'gap'))
    ->jitter(width: 0.3, height: 0.3, alpha: 0.5, seed: 1)
    ->labs(x: 'City mpg', y: 'Highway minus city mpg');

Field definitions

field() builds a Field with any Vega-Lite field-definition property, such as field('date', timeUnit: 'month', title: 'Month') or field('term', sort: ['b', 'a', 'c']). A raw array is also accepted for any aesthetic and is used as given.

Field names containing dots or brackets, such as R’s Sepal.Length, are escaped automatically. Vega-Lite would otherwise read them as nested access.

From phpstats/phiz@bc7ed3e.