Sources

Value & Palette Fields

A field is a fixed grid of cells. A ValueField holds numbers that a gradient colours. A PaletteField holds exact palette indices.

Updated Publisher Alien_AlgorithmsPine Script v6

Create a field

Two kinds of fieldpine
var pc.ValueField levels = pc.valueField(240, 400)       // rows, columns
var pc.PaletteField pixels = pc.paletteField(240, 400)   // rows, columns
  • valueField(rows, columns, initial = na) starts every cell at na, which is transparent.
  • paletteField(rows, columns, initial = -1) starts every cell at -1, which is transparent. Index 0 selects the first palette colour.
  • A field needs at least 1 row and from 1 to 100,000 columns. To be drawn it needs at least 2 rows and 2 columns.
  • The sizes are available afterwards as field.rows and field.columns.

Row 0 is the bottom row and column 0 is the left, oldest column. Call invertRows() on the Canvas when a picture is easier to write top-down.

Read and write cells

Cell accesspine
levels.set(row, column, 42.5)      // write one cell, returns the field
float value = levels.get(row, column)

pixels.set(row, column, 3)         // palette index 3
pixels.set(row, column, -1)        // transparent again

levels.fill(na)                    // every cell at once
pixels.fill(0)

set() and fill() return the field, so writes can chain. A row or column outside the field raises a runtime error.

Palette indices must exist
A palette field may only hold -1 or an index below the number of colours on the Canvas that draws it. Anything else stops the script with an error that names the valid range.

Whole rows with row()

row(rowIndex) returns a writable array that shares the storage of one row. Writing to it writes the field, without a method call or index arithmetic per cell.

Fill one row through its viewpine
array<float> cells = levels.row(row)
for column = 0 to levels.columns - 1
    cells.set(column, valueAt(row, column))
Do not resize a row view
The returned array is a slice of the field's storage. Setting its elements is the point. Pushing to it, clearing it, or resizing it is not supported.

Storage bands

A Pine array holds at most 100,000 elements, so a field keeps its cells in one or more bands, each a run of complete rows. A band holds as many rows as fit in one array, rounded down to a multiple of 32, so a small field usually has a single band. Loop over bandCount() instead of assuming one. Band access is the fastest way to write a large picture, and it is what Pine3D's rasterize() writes into.

CallReturns
bandCount()How many bands the field has, at least 1.
band(index)The writable array of one band, in row-major order.
bandStart(index)The field row that the band begins at.
bandRows(index)How many complete rows the band stores.

Inside a band, the cell at a field row and column sits at (row - bandStart(index)) * columns + column.

Write a large picture band by bandpine
for bandIndex = 0 to picture.bandCount() - 1
    array<int> cells = picture.band(bandIndex)
    int firstRow = picture.bandStart(bandIndex)
    for localRow = 0 to picture.bandRows(bandIndex) - 1
        int row = firstRow + localRow
        for column = 0 to picture.columns - 1
            cells.set(localRow * picture.columns + column, paletteIndexAt(row, column))

set(), row(), and band() all update the same storage, so they can be mixed freely.

Field stamps

Stamps write simple shapes straight into a field. They clip to the field's bounds and return the field. Coordinates are rows and columns, not prices.

CallWhat it writes
rect(row0, column0, row1, column1, value, filled = true)A filled rectangle, or only its outline when filled is false. The corners may be given in any order.
segment(row0, column0, row1, column1, value)A straight line of cells between two points.
circle(centerRow, centerColumn, radius, value, filled = false)A one-cell ring, or a disc when filled is true.
A complete indicator using stampspine
//@version=6
indicator("PineCanvas - Field Stamps", overlay = false, max_polylines_count = 100)
import Alien_Algorithms/PineCanvas/1 as pc

var pc.PaletteField board = pc.paletteField(40, 80)
var pc.Canvas canvas = pc.newCanvas(array.from(color.gray, color.orange, color.aqua))

if barstate.isfirst
    board.rect(0, 0, 39, 79, 0, false)   // an outline around the whole field
    board.segment(0, 0, 39, 79, 1)       // a diagonal line
    board.circle(20, 40, 12, 2, true)    // a filled disc

if barstate.islast and bar_index >= 80
    canvas.drawLookback(board, 0, 0.0, 40.0)

A stamped circle is round in cells. It looks round on the chart only when the cells are drawn square, which depends on the vertical bounds and the zoom.

Value field or palette field

Choose a ValueField when

The data is a magnitude and the colour should follow it: exposure, volume, probability, an oscillator. The Canvas maps the numbers through a gradient, and you can change the gradient, the level count, the range, or the gamma without rewriting a cell.

Choose a PaletteField when

Each cell has an exact colour: a picture, a rendered 3D frame, a market state. The palette is the Canvas's colour array, with 2 to 100 entries, and every index is drawn exactly as given.

PineCanvas is a graphics library for Pine Script. TradingView drawing, memory, and execution limits still apply. © Alien_Algorithms.