Canvas & Drawing

Canvas & Styling

A Canvas holds the colours and the style, and owns the drawings it creates. Every setter returns the Canvas, so a configuration reads as one chain.

Updated Publisher Alien_AlgorithmsPine Script v6

Two constructors

A plain Canvas and a heatmap presetpine
var pc.Canvas picture = pc.newCanvas(array.from(color.red, color.lime))
var pc.Canvas heat = pc.heatmap()
newCanvas(colors)heatmap(colors)
Colours when omittedBlack and whiteA five-stop thermal gradient
Colour levelsOne per colour given64
Opacity100 for every level15 at the lowest level to 90 at the highest
ScalingA fixed range of 0 to 1Automatic, over the whole grid

Use newCanvas() for palette sources, shapes, and value sources whose range you set yourself. Use heatmap() for numerical data that should scale to itself and let the chart show through its weak values.

A value source on a plain Canvas
newCanvas() starts with one level per colour it was given. For a smooth gradient from a few stops, add colorLevels() to the chain.

Palettes and gradients

A Canvas has one colour array of 2 to 100 entries. A palette source reads it as exact colours, where index 0 is the first entry. A value source reads it as gradient stops and samples between them.

Supplying colourspine
// Exact colours for a palette source
var pc.Canvas picture = pc.newCanvas(array.from(#1b2a41, #c96a3c, #f2c14e, #ffffff))

// Gradient stops for a value source
var pc.Canvas heat = pc.heatmap(pc.gradient(#602060, #305bb4, #31b6ad, #f4d24c, #f07735))

// Replace them later
heat.palette(pc.gradient(color.navy, color.yellow))
  • pc.gradient(lowColor, highColor) builds a two-stop array.
  • pc.gradient(color0, color25, color50, color75, color100) builds a five-stop array.
  • palette(colors) copies a new array into the Canvas. Any array<color> of 2 to 100 entries works.

From value to colour

A value source goes through four steps before it is drawn:

  • Range: the value is placed between 0 and 1, using the bounds from valueRange() or the data's own minimum and maximum under autoScale(). Values outside the range are clamped to its ends.
  • Gamma: the result is raised to the power set with gamma().
  • Level: it is quantized into one of the levels set with colorLevels().
  • Colour: the level takes its colour from the gradient and its opacity from the ramp set with opacity().

A palette source skips the first three steps. Its indices are the levels.

Colour levels

colorLevels(count) samples a value source's gradient into 2 to 100 levels. More levels give smoother shading and more geometry. Fewer give flat bands and larger regions. It has no effect on palette sources, which use their palette entries directly.

Opacity

A ramp, or one valuepine
heat.opacity(10, 90)   // weakest level 10, strongest level 90
heat.opacity(100)      // every level fully opaque
  • Both arguments run from 0 to 100. With one argument every level gets the same opacity.
  • The ramp is applied as a percentage of each colour's own opacity, so a palette colour that is already translucent stays translucent.
  • A level whose opacity works out to 0 is not drawn and takes no polyline.

Scaling

A fixed range

valueRange(minimum, maximum) maps one value to the lowest level and another to the highest, and turns automatic scaling off. A colour then means the same value on every update, which is what comparison needs.

Automatic scaling

autoScale(mode) takes the range from the data on every render.

ModeThe range comes from
pc.ScaleMode.wholeGridThe whole source. This is the default.
pc.ScaleMode.eachColumnEach column on its own, so every bar uses the full gradient.
pc.ScaleMode.eachRowEach row on its own, for rows with different natural ranges.
Automatic scaling re-colours the picture
When the data's extremes change, every colour shifts with them. That suits a picture read on its own. Use valueRange() when two frames, or two bars, must be compared.

Gamma

gamma(value) bends the response curve. The value must be greater than 0. Below 1 it lifts weak values into visible levels. Above 1 it suppresses them and keeps only the strong ones bright. At 1 the mapping is linear.

Layout switches

CallEffect
logarithmicY(enabled = true)Spaces the rows logarithmically between the bottom and top bounds, which must both be positive. It applies to regular placement, not to explicit grid edges.
invertRows(enabled = true)Puts row 0 at the top.
forceOverlay(enabled = true)Places the drawings on the main price chart, whatever pane the script runs in.
drawingLimit(count)Caps the polylines this Canvas may own, from 1 to 100.

Layers & Drawing Budgets explains how drawingLimit() divides the script's 100 polylines between canvases.

Style objects

Every setter above writes one field of the Canvas's Style. pc.newStyle(...) builds a complete one, and configure(style) applies it in one call. That is useful when several canvases share a look, or when the style comes from inputs.

One Style, applied in one callpine
pc.Style shared = pc.newStyle(colorLevels = 48, lowOpacity = 10.0, highOpacity = 90.0,
  autoScale = true, gamma = 0.7)

var pc.Canvas heat = pc.heatmap().configure(shared)
newStyle() parameters
SettingDefaultWhat it does
colorLevels64Colours sampled from the gradient, from 2 to 100.
lowOpacity15.0Opacity of the lowest level, from 0 to 100.
highOpacity90.0Opacity of the highest level, from 0 to 100.
autoScalefalseTake the value range from the data.
valueMin0.0Value mapped to the lowest level when autoScale is false.
valueMax1.0Value mapped to the highest level. It must exceed valueMin.
gamma1.0Exponent applied to the normalized value. It must be greater than 0.
logarithmicYfalseLogarithmic row spacing for regular placement.
invertRowsfalseRow 0 at the top.
forceOverlayfalseDraw on the main price chart.
scaleModeScaleMode.wholeGridWhat automatic scaling measures: the whole grid, each column, or each row.
drawingLimit100Polylines the Canvas may own, from 1 to 100.

Clear and inspect

CallReturns
clear()Deletes every polyline the Canvas owns, and returns the Canvas.
drawingCount()The number of polylines the Canvas currently owns.
componentCount()The number of same-colour regions the last field render found.
dimensions()A [rows, columns] tuple from the last field render.
scaledRange()A [minimum, maximum] tuple: the value range the last field render used.
Watch the counts in the Data Windowpine
plot(float(heat.componentCount()), "Heat regions", display = display.data_window)
plot(float(heat.drawingCount()), "Polylines", display = display.data_window)
PineCanvas is a graphics library for Pine Script. TradingView drawing, memory, and execution limits still apply. © Alien_Algorithms.