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.
Two constructors
var pc.Canvas picture = pc.newCanvas(array.from(color.red, color.lime))
var pc.Canvas heat = pc.heatmap()| newCanvas(colors) | heatmap(colors) | |
|---|---|---|
| Colours when omitted | Black and white | A five-stop thermal gradient |
| Colour levels | One per colour given | 64 |
| Opacity | 100 for every level | 15 at the lowest level to 90 at the highest |
| Scaling | A fixed range of 0 to 1 | Automatic, 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.
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.
// 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. Anyarray<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 underautoScale(). 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
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.
| Mode | The range comes from |
|---|---|
pc.ScaleMode.wholeGrid | The whole source. This is the default. |
pc.ScaleMode.eachColumn | Each column on its own, so every bar uses the full gradient. |
pc.ScaleMode.eachRow | Each row on its own, for rows with different natural ranges. |
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
| Call | Effect |
|---|---|
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.
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)| Setting | Default | What it does |
|---|---|---|
| colorLevels | 64 | Colours sampled from the gradient, from 2 to 100. |
| lowOpacity | 15.0 | Opacity of the lowest level, from 0 to 100. |
| highOpacity | 90.0 | Opacity of the highest level, from 0 to 100. |
| autoScale | false | Take the value range from the data. |
| valueMin | 0.0 | Value mapped to the lowest level when autoScale is false. |
| valueMax | 1.0 | Value mapped to the highest level. It must exceed valueMin. |
| gamma | 1.0 | Exponent applied to the normalized value. It must be greater than 0. |
| logarithmicY | false | Logarithmic row spacing for regular placement. |
| invertRows | false | Row 0 at the top. |
| forceOverlay | false | Draw on the main price chart. |
| scaleMode | ScaleMode.wholeGrid | What automatic scaling measures: the whole grid, each column, or each row. |
| drawingLimit | 100 | Polylines the Canvas may own, from 1 to 100. |
Clear and inspect
| Call | Returns |
|---|---|
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. |
plot(float(heat.componentCount()), "Heat regions", display = display.data_window)
plot(float(heat.drawingCount()), "Polylines", display = display.data_window)