Getting Started

Quickstart & Lifecycle

Raise the polyline budget, import the library, keep one source and one Canvas, fill the source, and draw once per update.

Updated Publisher Alien_AlgorithmsPine Script v6

Setup requirements

Required declaration and importpine
//@version=6
indicator("My Canvas", overlay = false, max_polylines_count = 100)

import Alien_Algorithms/PineCanvas/1 as pc

PineCanvas draws with polylines, so raise max_polylines_count to 100, which is the platform maximum. Imports are pinned to a version number. Use the latest one shown on the TradingView publication.

Your first picture

The last 30 candles, coloured by directionpine
//@version=6
indicator("PineCanvas - Candle Colours", overlay = false, max_polylines_count = 100)
import Alien_Algorithms/PineCanvas/1 as pc
// Make sure to update to the latest library version

var pc.PaletteField pixels = pc.paletteField(2, 30)
var pc.Canvas canvas = pc.newCanvas(array.from(color.red, color.lime))

if barstate.islast and bar_index >= 29
    for col = 0 to 29
        pixels.set(0, col, close[29 - col] >= open[29 - col] ? 1 : 0)
    canvas.drawLookback(pixels, 0, 0.0, 2.0)

A PaletteField holds colour indices in a grid. The Canvas is given a palette of two colours, each cell selects one of them, and one call draws the strip. Each candle contributes one coloured cell. The second row is never written, so it stays transparent.

The lifecycle

  • Create once: keep sources and canvases in var variables so they persist from bar to bar.
  • Fill the source: write values or palette indices into a field, or push one column per bar into a scroll.
  • Style the Canvas: choose the palette or gradient, the colour levels, opacity, gamma, and how values are scaled.
  • Draw once: call a draw method once per update, normally inside barstate.islast.
The core pattern
Create once, fill, draw once. A Canvas replaces its previous drawings every time it draws, so there is nothing to clean up between frames.

Rows, columns, and transparency

  • Row 0 is the bottom row. Call invertRows() on the Canvas to put row 0 at the top.
  • Column 0 is the left, oldest column. The last column is the newest.
  • Transparent cells cost nothing. In a value field that is na. In a palette field it is the index -1.

Both field constructors start every cell transparent, so a picture only pays for the cells it sets.

Your first heatmap

Five RSI lengths as a rolling heatmappine
//@version=6
indicator("PineCanvas - Rolling RSI Heatmap", overlay = false,
  max_polylines_count = 100)
import Alien_Algorithms/PineCanvas/1 as pc
// Make sure to update to the latest library version

// Stateful series calculations must run on every bar.
float rsi5 = ta.rsi(close, 5)
float rsi8 = ta.rsi(close, 8)
float rsi13 = ta.rsi(close, 13)
float rsi21 = ta.rsi(close, 21)
float rsi34 = ta.rsi(close, 34)

var pc.ValueScroll history = pc.valueScroll(5, 150)
var pc.Canvas heat = pc.heatmap(
  pc.gradient(#602060, #305bb4, #31b6ad, #f4d24c, #f07735))
  .colorLevels(32)
  .valueRange(0.0, 100.0)
  .opacity(25, 100)

if barstate.isconfirmed
    history.push(array.from(rsi5, rsi8, rsi13, rsi21, rsi34))

if barstate.islast
    heat.drawLookback(history, 0.0, 5.0)

A ValueScroll keeps a moving window when one new column arrives each bar. Five RSI lengths become five rows, and each confirmed bar pushes one column, bottom row first. pc.heatmap() returns a Canvas preset for numerical data, and valueRange(0, 100) pins the colours to the RSI scale so they mean the same thing on every bar.

A separate pane or the price chart

In a separate pane

With overlay = false the vertical bounds are just numbers. The first example draws between 0 and 2, the heatmap between 0 and 5.

On the price chart

With overlay = true, or with forceOverlay() on the Canvas, the bounds are prices. Pass the real lowest and highest price the picture should span, and it stays anchored to the candles. Placement & Coordinates covers every way to position a field.

Global-scope series calculations

Compute history-dependent values such as ta.rsi(), ta.sma(), ta.highest(), and request.security() at global scope, on every bar. Read their results inside the barstate.islast block afterwards. Calling them only on the last bar gives them no history to work from.

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